为什么 touchstart 事件会冻结我的程序?

问题描述 投票:0回答:1

我一直致力于开发一款视频游戏,最近一直致力于将触摸屏功能合并到该程序中。但是,我注意到触摸事件往往会导致画布中的运动冻结。

这是我编写的一些代码来演示这一点:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <canvas id="cnvs" width="400" height="400"></canvas>

        <script>
            var canvas, canvasContext;
            var x = 0, y = 30;
            var incrementor = 1;

            window.onload = function() {
                canvas = document.getElementById('cnvs');
                canvasContext = canvas.getContext('2d');

                colorRect(0, 0, canvas.width, canvas.height, 'white');

                setInterval(updateAll, 1);

                canvas.addEventListener('touchstart', touchStart);
                canvas.addEventListener('touchend', touchEnd);
            }

            function touchStart(e) {
                console.log(e);
            }

            function touchEnd(e) {
                console.log(e);
            }

            function colorRect(p,a,i,n,t) {
                canvasContext.fillStyle = t;
                canvasContext.fillRect(p,a,i,n);
            }

            function updateAll() {
                moveAll();
                drawAll();
            }

            function moveAll() {
                x += incrementor;

                if(x > canvas.width - 20 || x < 0) {
                    incrementor = incrementor * -1;
                }
            }

            function drawAll() {
                colorRect(0, 0, canvas.width, canvas.height, 'black');
                colorRect(x, y, 20, 20, 'red');
            }
        </script>
    </body>
</html>

请注意,当您使用带有触摸屏的设备触摸画布时,程序似乎有点“卡顿”。并不一定会出现错误。事实上,程序运行没有任何错误。出现的唯一“错误”是,当调用触摸事件时,画布上的移动往往会冻结。

我的主要问题是:如何编写一个与此类似的程序来执行完全相同的任务,但又不会在进程中冻结程序?我没有任何使用 jQuery 或任何其他精美 JS 插件的经验,因此使用纯 JavaScript 来完成此操作的方法将对我的事业有所帮助。

javascript performance html5-canvas touchstart
1个回答
0
投票

您可能遇到了处理器过度工作的问题。

JavaScript 有一个非常有用的方法可以实现更好的渲染性能,这就是

Window
方法
requestAnimationFrame(updateAll)
。就像
setInterval
但回调在浏览器呈现其内容的每一帧运行一次。

按照惯例,浏览器以 60fps 的速率渲染内容,该速率可以配置,也可以不配置。

但是您的代码使用

setInterval(updateAll, 1)
,这会导致您的代码每秒渲染图像一千次,而浏览器只会渲染其中的 60 次。您渲染的图像比需要的多 1940 倍。

请注意,这也是基于帧速率的测量,这很糟糕,因为如果它更大(例如 120fps),那么一切都会移动得更快而不是更平滑(游戏速度应该根据时间保持不变)。 .

由于后一个问题与实际问题无关,所以我将其放在一边。

使用下面的代码片段尝试您的代码:

var canvas, canvasContext;
var x = 0, y = 30;
var incrementor = 1;

// EDIT: Using this function to adjust the game velocity.
function speed(v) {
  incrementor = v;
}

window.onload = function() {
  canvas = document.getElementById('cnvs');
  canvasContext = canvas.getContext('2d');
  colorRect(0, 0, canvas.width, canvas.height, 'white');
  
  canvas.addEventListener('touchstart', touchStart);
  canvas.addEventListener('touchend', touchEnd);
  
  // EDIT: Refresh the image with initial data.
  updateAll();
}

function touchStart(e) {
  console.log(e);
}

function touchEnd(e) {
  console.log(e);
}

function colorRect(p,a,i,n,t) {
  canvasContext.fillStyle = t;
  canvasContext.fillRect(p,a,i,n);
}

function updateAll() {
  moveAll();
  drawAll();
  
  // EDIT: Refresh the image on the next frame renderization.
  requestAnimationFrame(updateAll);
}

function moveAll() {
  x += incrementor;

  if(x > canvas.width - 20 || x < 0) {
      incrementor = incrementor * -1;
  }
}

function drawAll() {
  colorRect(0, 0, canvas.width, canvas.height, 'black');
  colorRect(x, y, 20, 20, 'red');
}
<canvas id="cnvs" width="400" height="400"></canvas>
<div>
  <button onclick="speed(1)">Speed 1</button>
  <button onclick="speed(5)">Speed 5</button>
  <button onclick="speed(10)">Speed 10</button>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.