Javascript 移动版点击底部时游戏卡顿

Javascript game lagging when i tap a bottom in mobile version

我正在尝试在 javascript 上制作游戏。在计算机版本中它工作正常,但是当我尝试在移动版本中证明时(Google chrome > F12 > 切换设备工具栏或 Ctrl+Shift+M),游戏在点击 left/right 下装.

我曾尝试将 div 元素更改为按钮,但我真的不知道问题出在哪里。这不是一个复杂的游戏,至少我认为是这样。

代码如下:

var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");





    function getRandomColor() {
    var letters = '0123456789ABCDEF';
    var color = '#';
    for (var i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
    }

    //paleta
    var paddleHeight = 10;
    var paddleWidth = 75;
    var paddleXD = (canvas.width-paddleWidth)/2;
    var paddleXU = (canvas.width-paddleWidth)/2;

    var rightPressedU = false;
    var leftPressedU = false;

    var rightPressedD = false;
    var leftPressedD = false;

    document.addEventListener("keydown", keyDownHandlerD, false);
    document.addEventListener("keyup", keyUpHandlerD, false);
    document.addEventListener("keydown", keyDownHandlerU, false);
    document.addEventListener("keyup", keyUpHandlerU, false);

    document.getElementById("der").addEventListener("mousedown", function () {
        rightPressedD = true;
    }, false);
    document.getElementById("izq").addEventListener("mousedown", function () {
        leftPressedD = true;
    }, false);
    document.addEventListener("mouseup", function () {
        rightPressedD = false;
        leftPressedD = false;
    }, false)
    document.getElementById("der").addEventListener("touchstart", function () {
        rightPressedD = true;
    }, false);
    document.getElementById("izq").addEventListener("touchstart", function () {
        leftPressedD = true;
    }, false);
    document.addEventListener("touchend", function () {
        rightPressedD = false;
        leftPressedD = false;
    }, false)

    //flechas (ABAJO)
    function keyDownHandlerD(e) {
        if(e.keyCode == 39) {
            rightPressedD = true;
        }
        else if(e.keyCode == 37) {
            leftPressedD = true;
        }
    }

    function keyUpHandlerD(e) {
        if(e.keyCode == 39) {
            rightPressedD = false;
        }
        else if(e.keyCode == 37) {
            leftPressedD = false;
        }
    }


    //A y D ARRIBA
    function keyDownHandlerU(e) {
        if(e.keyCode == 100) {
            rightPressedU = true;
        }
        else if(e.keyCode == 97) {
            leftPressedU = true;
        }
    }

    function keyUpHandlerU(e) {
        if(e.keyCode == 100) {
            rightPressedU = false;
        }
        else if(e.keyCode == 97) {
            leftPressedU = false;
        }
    }


    //lugar donde aparecerá la bola
    var x = canvas.width/2;
    var y = canvas.height-30;

    //esto es la 'velocidad', los pixeles que recorren cada 10 milisegundos.
    var dx = 2;
    var dy = -2;

    //el radio del balon
    var ballRadius = 10;


    function drawBall() {//esto simplemente pinta la bola
        ctx.beginPath();
        ctx.arc(x, y, ballRadius, 0, Math.PI*2);
        //ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
    }
    function drawPaddleU() {
        ctx.beginPath();
        ctx.rect(paddleXU, 0, paddleWidth, paddleHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
    }
    function drawPaddleD() {
        ctx.beginPath();
        ctx.rect(paddleXD, canvas.height-paddleHeight, paddleWidth, paddleHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
    }

    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        drawBall();
        drawPaddleD();
        drawPaddleU();

        if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
            dx = -dx;
            //ctx.fillStyle = getRandomColor();
        }
        if(y + dy < ballRadius) {
            dy = -dy;
        } else if(y + dy > canvas.height-ballRadius) {
            if(x > paddleXD && x < paddleXD + paddleWidth) {
                dy = -dy;
            }
            else {
                //alert("GAME OVER");
                document.location.reload();
            }
        }
        if(rightPressedD && paddleXD < canvas.width-paddleWidth) {
            paddleXD += 7;
        }
        else if(leftPressedD && paddleXD > 0) {
            paddleXD -= 7;
        }

        if(rightPressedU && paddleXU < canvas.width-paddleWidth) {
            paddleXU += 7;
        }
        else if(leftPressedU && paddleXU > 0) {
            paddleXU -= 7;
        }
        x += dx;
        y += dy;
    }
    



        //document.write("la bola esta en X: "+x+" Y: "+y);
    

    setInterval(draw,10);
* { padding: 0; margin: 0; }
     canvas { background: #eee; display: block; margin: 0 auto; border: 1px solid black;}
        table{touch-action: manipulation;}
        #izq{
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }
        #der{
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>game</title>
</head>
<body>
<center>
<table>
<tr >
    <td colspan="2">
        <canvas id="myCanvas" width="480" height="320"></canvas>
    </td>
</tr>
<tr>
    <td>
        <div id="izq" style="background-color: green; width: 240px; height: 160px;">left</div>
    </td>
    <td>
        <div id="der" style="background-color: green; width: 240px; height: 160px;">right</div>
    </td>
</tr>
</table>
</center>

</body>
</html>

这也发生在我身上,我不知道问题出在哪里。我提交的 bug report to the Chrome team, and the response 如下:

I believe this is expected. If you add an event listener, a touchstart may indicate that scrolling is about to happen (Chrome can't tell a priori whether the event will be preventDefaulted). We thus avoid scheduling any Javascript tasks like timers to ensure touch handlers remain responsive so the potential upcoming scroll can start ASAP.

因此,基本上,Chrome 会在用户开始触摸屏幕后停止计时器一段时间,以确保滚动响应。

有两种简单的方法可以避免这种情况:

  1. 使用passive event listeners

    This is a promise to Chrome that the handler doesn't call ev.preventDefault() so we can tell ahead of time that a touch drag will cause scrolling. Because of that, when we're ready to scroll (off the Javascript thread) we don't have to wait for handlers to respond and we can scroll immediately, so we don't have to keep the JS thread idle to get responsiveness.

    document.getElementById("der").addEventListener("touchstart", function () {
        rightPressedD = true;
    }, {passive: true});
    
  2. 致电ev.preventDefault()。这将阻止滚动、click 事件和其他内容,但可能会带来更好的性能。

    document.getElementById("der").addEventListener("touchstart", function (ev) { // You need to use the first argument
        ev.preventDefault();
        rightPressedD = true;
    });
    

请确保永远不要在被动事件侦听器中调用 ev.preventDefault(),否则会出错。