Html 我的游戏循环中的帧抖动

Html 我的游戏循环中的帧抖动,html,canvas,2d-games,game-loop,Html,Canvas,2d Games,Game Loop,我希望有人能指出我的代码出了什么问题,因为我已经看了足够长的时间,以至于发疯了。我正在使用HTML5实现一个侧面滚动自动运行程序,并且遇到了一些帧速率抖动的问题。它在我的Macbook Air上运行得非常好,在Nexus 4上也几乎一样好,但当我部署到iPhone4上时,我注意到帧速率出现了一些恼人的抖动。请记住,我使用的是CocoonJS,因此画布性能应该没有问题 我花了很长时间研究可能的性能问题,但当我后退一步时,它似乎比这更基本。看来问题可能与我的游戏循环本身有关。我创建了一个更基本的示例

我希望有人能指出我的代码出了什么问题,因为我已经看了足够长的时间,以至于发疯了。我正在使用HTML5实现一个侧面滚动自动运行程序,并且遇到了一些帧速率抖动的问题。它在我的Macbook Air上运行得非常好,在Nexus 4上也几乎一样好,但当我部署到iPhone4上时,我注意到帧速率出现了一些恼人的抖动。请记住,我使用的是CocoonJS,因此画布性能应该没有问题

我花了很长时间研究可能的性能问题,但当我后退一步时,它似乎比这更基本。看来问题可能与我的游戏循环本身有关。我创建了一个更基本的示例,它再现了与我相同的问题。这是一个又快又脏的代码,所以很抱歉,但它说明了我的问题

我通过这里的一个例子实现了一个游戏循环。我没有实现插值,因为我不认为有必要实现这种基本的东西。为了更接近低端设备,我在控制台上写了一个for循环(脏的,我知道),所以在打开web调试器的情况下,我在macbookair上得到了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>

设置间隔示例
Game.initialize();
Game.run=(函数(){
var循环=0,skipTicks=1000/Game.ups,
maxFrameSkip=20,
nextGameTick=(新日期).getTime();
返回函数(){
循环=0;
while((新日期).getTime()>nextGameTick&&loops=1000){
this.fps=this.frames;
this.previousTime=this.currentTime;
这个.currentTime=0;
这是0.frames=0;
}
};
Game.drawFrames=函数(){
this.context.fillText(“UPS:+this.UPS,20180);
this.context.fillText(“FPS:+this.FPS,20150);
};
////////直肠///////////
函数Rect(x,y){
这个.x=x;
这个。y=y;
速度=-4;
};
Rect.prototype.draw=函数(上下文){
context.fillRect(this.x,this.y,30,30);
};
Rect.prototype.update=函数(){
如果(此.x<-30){
这个.x=640;
} 
这个.x+=这个速度;
};

我认为问题可能只是iPhone 4运行了某种昂贵的内部流程,导致您的UPS比FPS更大。它正在创建一个巨大的增量。除了多次调用
update
来尝试捕捉之外,循环无法捕捉任何东西,直到sprite位置被捕捉,然后这导致了你看到的跳跃。我不认为这是你可以控制的。你的代码看起来像经典的固定时间步长变量渲染,所以我认为问题出在iPhone 4上。但我可能错了,所以希望其他人可以对此发表评论。我同意@d13的说法,你的延迟可能是由于设备限制。Mobile几乎没有er资源来处理所需的系统活动,因此FPS将受到影响。这可能有助于将
requestAnimationFrame
替换为
setInterval
。RAF将自身与设备刷新周期同步,并可能减少所需系统活动期间的延迟。RAF的新版本提供了一个时间戳参数,您可以使用该参数来驱动即使由于系统活动而丢失了一帧,请重新定位游戏元素。嗨,伙计们,谢谢你们的评论。问题是,我在游戏中显示了UPS和FPS,而FPS从不显示(即使它滞后)下降到UPS下方。最坏情况下,我的UPS是恒定的30,FPS是45。当然,如果是这种情况,那么我不应该看到任何延迟?其他人可以提供一些见解。我实际上在我的macbook air上稍微注意到了这一点,所以我知道它不是特定于硬件的
////// 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;
};