【问题标题】:How to properly remove a ball from an HTML-5 canvas when the player hovers on it?当玩家悬停在球上时,如何从 HTML-5 画布中正确移除球?
【发布时间】:2018-12-23 09:49:07
【问题描述】:

我开发了一个小游戏,要求玩家只“吃” HTML5 画布中的绿球才能成功。

我已经到了当你悬停在球上时它会被吃掉的部分。但是出现了一些非常奇怪的行为。不是只有一个球被吃掉,而是一大堆突然消失了。

这是我的代码:

body {
    overflow: hidden;
    background: rgba(82, 80, 78, 0.75)
}

#gameCanvas {
    border: 0.25em solid black;
    background-color: rgba(255,235,205,0.5);
    margin-top: 1.25vh;
}

* {
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    font-size: 100%;
    vertical-align: baseline;
    background: transparent;
}

#flexContainer {
    margin-top: 0.5em;
    font-family: Verdana;
    font-size: 2.5em;
    display: flex;
    justify-content: space-around;
}

#flexContainer span{
    background: rgba(255, 180, 0, 0.50);
    transition-duration: 0.5s;
    padding: 0.1em;
    border-radius:0.25em;
}

#flexContainer span:hover {
    background: rgba(255, 180, 0, 0.8);
    transition-duration: 0.5s;
    border-radius: 1em;
    cursor:pointer;
}
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <link type="text/css" rel="stylesheet" href="EatTheBall.css" />
    <meta charset="utf-8" />
    <title>EatTheBall!</title>
</head>
<body>
    <div id="flexContainer">
        <span id="49" onclick="changeNumBalls();">Level 1</span>
        <span id="30" onclick="changeNumBalls();">Level 2</span>
        <span id="20" onclick="changeNumBalls();">Level 3</span>
        <span id="10" onclick="changeNumBalls();">Level 4</span>
        <span id="0" onclick="changeNumBalls();">Level 5</span>
    </div>
    <canvas id="gameCanvas"></canvas>
    <!--Start of JavaScript code-->
    <script>
        var XPos = 0;
        var YPos = 0;

        var n = 40;

        var gameCanvas = document.body.querySelector("#gameCanvas");
        var ctx = gameCanvas.getContext("2d");

        var colorArray = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];
        var balls = [];

        window.onload = function initial() {
            gameCanvas.height = 0.9 * window.innerHeight;
            gameCanvas.width = 0.995 * window.innerWidth;

            window.addEventListener("resize", function (evt) {
                gameCanvas.height = 0.9 * window.innerHeight;
                gameCanvas.width = 0.995 * window.innerWidth;
                gameCanvas.style.marginTop = (1.25 * window*innerHeight) +"vh";
            })
            movePlayer();
            MainLoop(); 
            addBalls();
        }

        function MainLoop() {
            ctx.clearRect(0, 0, gameCanvas.width, gameCanvas.height);
  
            drawBalls(balls);
            animateBalls(balls);

            requestAnimationFrame(MainLoop);
        }

        function addBalls() {
            while (n < 50) {
                n++;
                var b = {
                    x: window.innerWidth / 2,
                    y: window.innerHeight / 2,
                    radius: Math.random() * 30 + 15,
                    speedX: -7.5 + Math.random() * 15,
                    speedY: -7.5 + Math.random() * 15,
                    color : colorArray[Math.round(Math.random() * 6)]
                }
                balls.push(b);
            }
        }
        function drawBalls(ballArray) {
            ballArray.forEach(function (b) {
                drawOneBall(b);
            });
            drawPlayer();
        }
        function animateBalls(ballArray) {
            ballArray.forEach(function (b) {
                b.x += b.speedX;
                b.y += b.speedY;
                testCollisionBallWithWalls(b);
            });   
        }
        function drawOneBall(b) {
            ctx.save();
            ctx.beginPath();
            ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2);
            ctx.fillStyle = b.color;
            ctx.fill();
            ctx.restore();
        }
        function testCollisionBallWithWalls(b) {
            if ((b.x + b.radius > gameCanvas.width) || (b.x - b.radius < 0)) {
                b.speedX = -b.speedX;
            };
            if ((b.y + b.radius > gameCanvas.height) || (b.y - b.radius < 0)) {
                b.speedY = -b.speedY;
            };
            if (XPos > b.x - b.radius && XPos < b.x + b.radius && YPos > b.y - b.radius && YPos < b.y + b.radius) {
                balls.splice(b, 1);
            }
            if (XPos < b.x - b.radius && XPos > b.x + b.radius && YPos < b.y - b.radius && YPos > b.y + b.radius) {
                balls.splice(b, 1);
            }
        }
        function changeNumBalls() {
            n = event.currentTarget.id;
            balls = [];
            addBalls();
            drawBalls(balls);
            animateBalls(balls);
        }
        function drawPlayer() {
            ctx.save();
            ctx.fillStyle = "red";
            ctx.fillRect(XPos, YPos, 30, 30);
            ctx.restore();
        }
        function movePlayer() {
            gameCanvas.addEventListener("mousemove", function (evt) {
                XPos = evt.clientX - 15;
                YPos = evt.clientY - 100;
            })
        }
    </script>
</body>
</html>

代码解释时间!

我的想法是,我在开头声明了一个名为“balls”的变量,并为它分配了一个空数组的值。然后使用 while 循环创建球。 while 循环不断向空数组添加新的对象字面量,这些字面量描述了球的属性(也就是球中心的位置、半径的长度等)。接下来我调用 2 个函数,其中一个函数使用已添加到数组中的每个对象字面量中的属性实际绘制球。另一个用于为球设置动画。我在这两个函数中都使用了 forEach() 方法。

至于播放器,我在画布中创建了一个 fillRect()。我使用 canvas.addEventListener('mouseover', ...) 将 x1 和 y1 属性*设置为光标的位置


*fillRect(x1, y1, x2, y2)
接下来是棘手的部分...

碰撞检测!

每当玩家进入其中一个球时,球应该会使用 array.splice() 方法自动消失。但是,这不会发生。如前所述,消失的不是只有一个球,而是不止一个。

我实际上已经深入了解问题究竟是如何产生的。当球与玩家发生碰撞时,如果不使用 array.splice(),而只是在控制台中显示一条随机消息(console.log(random shit)),则该消息不会只显示一次,会显示多次


如果我的解释不够清楚,请自行检查代码并尝试理解它。我会非常感谢,在此先感谢。

【问题讨论】:

    标签: javascript animation html5-canvas 2d-games


    【解决方案1】:

    splice() 方法需要索引作为开始更改数组的第一个参数。在这种情况下,balls.indexOf(b) 可以给出 ball 在数组 balls 中的位置。所以它会起作用,如果你稍微改变一下 testCollisionBallWithWalls 函数:

    function testCollisionBallWithWalls(b) {
       if ((b.x + b.radius > gameCanvas.width) || (b.x - b.radius < 0)) {
          b.speedX = -b.speedX;
       };
    
       if ((b.y + b.radius > gameCanvas.height) || (b.y - b.radius < 0)) {
           b.speedY = -b.speedY;
       };
    
       if (XPos > b.x - b.radius && XPos < b.x + b.radius && YPos > b.y - 
       b.radius && YPos < b.y + b.radius) {
          balls.splice(balls.indexOf(b), 1);
       }
    }
    

    【讨论】:

    • 更新:嘿,我犯了一个错误。我只复制了:函数的最后一部分,而不是您编写的整个函数。当我复制整个文件时,它确实有效!谢谢!
    猜你喜欢
    • 2021-09-27
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-25
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    相关资源
    最近更新 更多