使用 setinterval 和 settimeout 时乒乓球拍滴答作响

pong paddles ticking when using setinterval and settiomeout

所以我正在尝试创建一个乒乓球游戏,乒乓球的拍子很响.. 我正在为球和球拍使用两个功能,我也在使用 canvas 运动有桨叶对象和事件监听器 请帮助:)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Pong</title>
    <script type="text/javascript">

        function canvas() {
            var can = document.getElementById('theCanvas');
            can.style.backgroundColor = "black";
            var ctx = can.getContext('2d');
            var keys = [];
            
        var ball = {    
            x: (can.width-10)/2,
            y: (can.width-10)/2,
            dx: 8,
            dy: 8
            }
        
        var playerOne = {
            x: can.width-50,
            y: (can.width-50)/2,
            H: 100,
            W: 20,
            hitDir: 0
        }
        
        var playerTwo = {
            x: 50,
            y: (can.width-50)/2,
            H: 100,
            W: 20,
            hitDir: 0
        }
            ctx.fillStyle ="white";
            ctx.fillRect(playerOne.x,playerOne.y,playerOne.W,playerOne.H);
            ctx.fillRect(playerTwo.x,playerTwo.y,playerTwo.W,playerTwo.H);
            
            function draw()
            {
            ctx.clearRect(0,0, 800,800);
            ctx.beginPath();
            ctx.fillStyle="#0000ff";
            ctx.arc(ball.x,ball.y,10,0,Math.PI*2,true);
            ctx.closePath();
            ctx.fill();
            if( ball.x<10 || ball.x>790) 
            {
            ball.dx=-ball.dx
            }
            
            if( ball.y<10 || ball.y>790) {
                ball.dy=-ball.dy
            }
            ball.x+=ball.dx; 
            ball.y+=ball.dy;
            
            ctx.fillStyle ="white";
            ctx.fillRect(playerOne.x,playerOne.y,playerOne.W,playerOne.H);
            ctx.fillRect(playerTwo.x,playerTwo.y,playerTwo.W,playerTwo.H);
            
            }
            setInterval(draw,10);

            function move() {
                ctx.clearRect(0,0,800,800);
                if (keys[38]) {
                playerTwo.y-=10;
            }

                if (keys[40]) {
                playerTwo.y+=10;
            
            }
            ctx.fillStyle ="white";
            ctx.fillRect(playerOne.x,playerOne.y,playerOne.W,playerOne.H);
            ctx.fillRect(playerTwo.x,playerTwo.y,playerTwo.W,playerTwo.H);
            ctx.clearRect(0,0, 800,800);
            ctx.beginPath();
            ctx.fillStyle="#0000ff";
            ctx.arc(ball.x,ball.y,10,0,Math.PI*2,true);
            ctx.closePath();
            ctx.fill();
            setTimeout(move, 1000/60);
            }
            move();
            document.body.addEventListener("keydown", function (e) {
            keys[e.keyCode] = true;
            });
            document.body.addEventListener("keyup", function (e) {
            keys[e.keyCode] = false;
            });
            
             }
             
    </script>
</head>
<body onload="canvas()">
    <canvas id="theCanvas" width="800" height="800"></canvas>
</body>
</html>

感谢您提出有趣的问题。

您要做的是将两个 setInterval/setTimeout 组合成一个渲染函数。然后由单个 window.requestAnimationFrame 函数使用,当浏览器准备好绘制下一帧时调用该函数。这优于 setTimeout 或 setInterval,这可能是 "ticking" 的原因,因为您的 canvas 可能在浏览器尚未准备好呈现该帧时尝试绘制该帧。

我也将您的游戏重构为以下伪代码

1) Set up the canvas and event listeners
2) Declare the render function
  2a) Change the position data of the ball & paddles
  2b) Render the ball & paddles based on its data
  2c) request another animation frame
3) request an animation frame with the render function

Here is my jsfiddle