Javascript setInterval for game draw loop未一致运行
Javascript setInterval for game draw loop not running consistently
我正在开发一个使用Node.js作为服务器的多人游戏。目前,它只是一个2D三角形,玩家可以在屏幕上行驶。游戏循环在服务器上运行,并将游戏世界状态的更新发送到客户端。客户端有一个绘制循环,该循环使用更新的位置和方向将三角形绘制到画布上。
问题:
我使用间隔为 30 毫秒的 setInterval 进行绘制循环。但是,游戏的运动可能会变得相当紧张。我尝试测量从一个循环开始到下一个循环所需的时间,如下面的代码所示。结果表明,环路之间的时间在1ms到200ms之间。
控制台输出示例:
looptime: 59
looptime: 14
looptime: 22
looptime: 148
looptime: 27
我运行客户端的唯一其他东西是 onkeyup/onkeydown 侦听器和 socket.io 侦听器将数据发送到服务器。任何帮助都非常感谢。
法典:
...
function init(){
var canvas = document.getElementById('canvas');
if(canvas.getContext){
setInterval(draw, 30);
}
}
function draw(){
timeNow = new Date().getTime();
console.log('looptime: '+(timeNow-startDrawTime));
startDrawTime = new Date().getTime();
var ctx = document.getElementById('canvas').getContext('2d');
triX = tri.pos.x;
triY = tri.pos.y;
ctx.save();
ctx.clearRect(0,0,400,400);// clear canvas
ctx.save();
ctx.translate(triX, triY);
ctx.rotate(tri.orientation);
ctx.save();
ctx.beginPath();
ctx.arc(0,0,5,0,Math.PI*2, true);
ctx.stroke();
ctx.restore();
//draw tri
ctx.save();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.moveTo(0, -5);
ctx.lineTo(5, 5);
ctx.lineTo(-5, 5);
ctx.closePath();
ctx.fill();
ctx.restore();
ctx.restore();
ctx.restore();
//console.log('looptime: '+((new Date().getTime())-time));
}
这就是 setTimeout 的设计方式。Javascript是按顺序运行的,如果完成一个循环需要更长的时间,那么完成循环则需要更长的时间。
在这种情况下,使其保持一致仅仅是性能问题,并且您的代码有很多粗糙的地方。我用一些性能改进对其进行了注释。
它在Firefox中运行缓慢的原因是因为console.log
语句。把它拿出来,它会运行得更快。控制台.log Chrome 曾经也很慢,我只有开发版本,但我认为它早已修复。任何调试器运行都会变慢,这是正常的。
function init() {
// Never ever reference the DOM unless you absolutely have to
// So we do it once, here, outside of the loop
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
if (canvas.getContext) {
setInterval(draw, 30, canvas, ctx);
}
}
function draw(canvas, ctx) {
timeNow = new Date().getTime();
// console statements can be slow in some browsers, so make sure they're gone from the final product
console.log('looptime: ' + (timeNow - startDrawTime));
startDrawTime = new Date().getTime();
triX = tri.pos.x;
triY = tri.pos.y;
// This clears the transformation matrix and resets the canvas
canvas.width = canvas.width;
ctx.save();
ctx.translate(triX, triY);
ctx.rotate(tri.orientation);
ctx.beginPath();
ctx.arc(0, 0, 5, 0, Math.PI * 2, true);
ctx.stroke();
ctx.restore();
//draw tri
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.moveTo(0, -5);
ctx.lineTo(5, 5);
ctx.lineTo(-5, 5);
// no need to close the path since we aren't stroking
ctx.fill();
//console.log('looptime: '+((new Date().getTime())-time));
}
所以你可以做一些事情来提高性能。首先是缓存您的上下文。把它放在绘制函数之外的变量中,
var ctx = document.getElementById('canvas').getContext('2d');
然后只需在绘制函数中引用ctx
。否则,您正在搜索 dom EACH 循环,这可能很昂贵。
我建议的下一件事是使用requestAnimationFrame
而不是setTimeout
// requestAnim shim layer by Paul Irish
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
MDN 源
基本上,您的浏览器控制何时需要重新绘制,为您提供更流畅的动画/移动。上述填充码回退到不支持setTimeout
,但由于您正在制作canvas
游戏,因此无论您使用的浏览器如何,都应该支持它。
你会像这样实现它
draw(){
// All your other code etc..
requestAnimFrame( function(){draw()} );
}
- 如何使用phaser使html5游戏在移动设备浏览器上运行
- 使用压缩的JavaScript文件(不是运行时压缩)
- Javascript运行php文件,然后下载文件
- chrome扩展:尽管运行了at:documentidle,js脚本还是过早启动
- 我已经创建了一个jquery转盘,并使用if条件来运行和停止转盘
- Angularjs代码未在匿名函数中运行
- jquery设置为使用参数运行
- 如何根据时间运行不同的脚本
- Meteor方法在客户端返回null,在客户端运行的相同方法返回正确的值
- 将文本框链接到由按钮运行的javascript公式
- 为什么不是't运行此Javascript的Chrome
- ng应用程序使脚本无限运行
- 如何在运行时在angular 2中加载外部js脚本
- 与运行长作业(javascript,node.js)的第三方API同步的最佳实践
- JavaScript错误:Microsoft JScript运行时错误:应为对象
- 在终端中运行 JavaScript 时(使用 rhino),如何使用 print() 函数在一行中打印
- for loop, Math.random() 不按预期运行
- Javascript setInterval for game draw loop未一致运行
- Jquery Ajax Call In For Loop只运行一次-可能存在Timing&退出条件
- 我可以以60fps的速度运行angular's digest loop来显示快速计时器吗?