我希望有人能够指出我的代码出了什么问题,因为我已经看了很长时间才发疯。我正在使用HTML5实现一个横向滚动的自动运行器,并遇到帧速率抖动的一些问题。它在我的Macbook Air上完美运行,在我的Nexus 4上几乎同样出色,但是当我部署到我的iPhone 4时,我注意到帧速率有些烦人的抽搐。请记住,我正在使用CocoonJS,因此Canvas性能应该没有问题。
我花了很多年时间调查可能出现的性能问题,但是当我退后一步时,它似乎比那些更基本的东西。似乎问题可能在于我的游戏循环本身。我创建了一个更基本的例子来重现我遇到的同样问题。这是快速而肮脏的代码,所以为此道歉,但它证明了我的问题。
通过查看http://www.koonsolo.com/news/dewitters-gameloop/comment-page-2/#comment-3877中的一个示例,我实现了一个游戏循环。我没有实现插值,因为我不认为这是基本的东西是必要的。为了更接近低端设备,我已经向控制台写了一个for循环写入(脏,我知道),所以打开web调试器我的Macbook Air上有30 UPS和~60FPS。
有时候,当帧速率下降时,我会经历这个帧抖动,屏幕上的移动块跳跃显着的数量。我的理解是,只要我的FPS保持在UPS之上,那么我就不应该注意到这种行为。要查看我的意思,只需取消注释for循环。
有人可以指出这里的问题是什么吗?或者如果这甚至是有效的测试?任何帮助非常感谢!
HTML
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>setInterval Example</title>
<script type="text/javascript" charset="utf-8" src="./test.js"></script>
</head>
<body>
<canvas id="viewport" height="480" width="640"></canvas>
<script type="text/javascript" charset="utf-8">
Game.initialize();
Game.run = (function() {
var loops = 0, skipTicks = 1000 / Game.ups,
maxFrameSkip = 20,
nextGameTick = (new Date).getTime();
return function() {
loops = 0;
while ((new Date).getTime() > nextGameTick && loops < maxFrameSkip) {
//for(var i = 0; i <= 250; i++) { console.log('test') }
Game.update();
nextGameTick += skipTicks;
loops++;
Game.logUpdate();
}
Game.draw();
Game.drawFrames();
Game.logFrame();
};
})();
window.setInterval(Game.run, 0);
</script>
</body>
</html>
JS
////// GAME //////////
var Game = {};
Game.ups = 30;
Game.initialize = function() {
this.frames = 0;
this.updates = 0;
this.updatesPerSecond=0;
this.blockA = new Rect(50, 50);
this.blockB = new Rect(250, 50);
this.blockC = new Rect(500, 50);
this.context = document.getElementById("viewport").getContext("2d");
this.context.font = "bold 18px Arial";
this.previousUpdateTime = 0;
this.previousTime = 0;
};
Game.draw = function() {
this.context.clearRect(0, 0, 640, 480);
this.blockA.draw(this.context);
this.blockB.draw(this.context);
this.blockC.draw(this.context);
};
Game.update = function() {
this.blockA.update();
this.blockB.update();
this.blockC.update();
};
Game.logUpdate = function() {
this.updates++;
this.currentUpdateTime = new Date().getTime();
if((this.currentUpdateTime - this.previousUpdateTime) >= 1000) {
this.updatesPerSecond = this.updates;
this.previousUpdateTime = this.currentUpdateTime;
this.currentUpdateTime = 0;
this.updates = 0;
}
};
Game.logFrame = function(){
this.frames++;
this.currentTime = new Date().getTime();
if((this.currentTime - this.previousTime) >= 1000) {
this.fps = this.frames;
this.previousTime = this.currentTime;
this.currentTime = 0;
this.frames = 0;
}
};
Game.drawFrames = function() {
this.context.fillText("UPS: " + this.ups, 20, 180);
this.context.fillText("FPS: " + this.fps, 20, 150);
};
//////// RECT ///////////
function Rect(x, y) {
this.x = x;
this.y = y;
this.velocity = -4;
};
Rect.prototype.draw = function(context) {
context.fillRect(this.x, this.y, 30, 30);
};
Rect.prototype.update = function() {
if (this.x < -30) {
this.x = 640;
}
this.x += this.velocity;
};