2012-08-05 51 views
3

我简化了我的游戏循环,只是一个在屏幕上移动的框,Click Here。出于某种原因,盒子似乎并不平稳。我做了一个video of it here带游戏循环的JavaScript流畅动画

游戏循环被称为像这样:

var game = function() { 
    var now = Date.now(); 
    var delta = now - then; 

    update(delta/1000); 
    draw(); 

    then = now; 
}; 

setInterval(game, 1000/50); 

我试图分离主游戏循环的draw电话,把他们在​​,但问题仍然存在。我看过一些看起来运行顺利的教程。我甚至尝试过使用fixed time-step game loop,但这让我的游戏运行速度难以控制。

我该如何改进上述逻辑,或许利用​​和维护deltaTime来调用update

+0

我完全没有看到它,它也一直说'59'。那是fps吗? – Esailija 2012-08-05 20:38:09

+0

嗯,是的59是我每秒显示更新次数的尝试。在我的Mac和Safari浏览器中,我看到桨和球向前跳一点,而不是平稳移动。我想我应该在其他一些电脑上检查它。 – Quantastical 2012-08-05 20:44:49

+0

如果我仔细观察球的话,我猜球有点不舒服......这是因为在某些帧中,球一次移动超过1px。 – Esailija 2012-08-05 20:45:38

回答

3

我相信在使用画布时,您的位置变量应该是整数值,因为它们表示像素和浮点值没有意义。如果你打开控制台并输入sceneManager.currentScene.GameplayLayer.ball.position.x,那么你会得到一个非常长的小数。我认为对OP的评论表明,有时球移动2px而不是1px可能会对某事产生影响。当你更新你的位置时,你最终得到一个浮点值。

我相信它有时会舍入到下一个最高像素位置,有时会下降。我会尝试采取在地面或天花板上,像这样:

this.position.x += Math.floor(this.speed * 100 * deltaTime * Math.cos(directionInRadians)); 
this.position.y += Math.floor(this.speed * 100 * deltaTime * Math.sin(directionInRadians)); 

我会做这些改变的,看看它是如何工作。

编辑:由于你编辑你的问题来简化逻辑。我可以建议一些尝试,即使用我创建的Clock对象,这是我一直使用的。它给了我流畅的动画,而且非常简单。它基于clock that Three.JS uses,因此您可能也想检查一下。即使你想使用你自己的代码,你至少可以尝试这个现成的解决方案,看看它是否给你相同的结果。它似乎对我来说工作得很好。另外,您尝试使用垫片,因此您在游戏功能中的呼叫应该是requestAnimFrame(game);

var Clock = function() { 

    /** Member startTime will remain fixed at its integer 
     millisecond value returned by Date.now(). Will always 
     be equal to the time the clock was started */ 
    this.startTime = Date.now(); 

    /** Member ms is updated by tick() to a integer value reprsenting 
     the number of milliseconds between the epoch (January 1, 1970) 
     and the current date and time of the system. */ 
    this.ms = this.startTime; 
    this.last = this.startTime; /** millis at last call to tick() */ 
    this.time = 0;    /** ms in floating point seconds not millis */ 

    /** Member dt is updated by tick() to an integer value representing 
     the number of milliseconds since the last call to tick(). */ 
    this.dt = 0; 
    this.delta = 0; /** dt in floating point seconds not millis */ 

    /** Member fps is updated by tick() to a floating point value representing 
     frames per second, updated and averaged approximately once per second */ 
    this.fps = 0.0; 

    /** Member frameCount is updated to an integer value representing the 
     total number of calls to tick() since the clock was created. */ 
    this.frameCount = 0; 

    /** The frameCounter member is a flag you can turn off if you don't need to 
     calculate the frameCount or do the average FPS calculation every second */ 
    this.frameCounter = true; 

    /** Private globals needed to calculcate/average fps over eachs second */ 
    var timeToUpdate = 0; 
    var framesToUpdate = 0; 

    /************************************************************************************ 
     The tick() method updates ALL the Clock members, which should only 
     be read from and never written to manually. It is recommended that 
     tick() is called from a callback loop using requestAnimationFrame 

     Learn more: http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 
    *************************************************************************************/ 
    this.tick = function() { 
     /** This is a new frame with it's very own unique number */ 

     if (this.frameCounter) this.frameCount++; 

     /** Set the private currentTime variable */ 
     this.ms = Date.now(); 

     /** Update time delta and immediately set last time to 
      be as accurate as possible in our timings. */ 
     this.dt = this.ms - this.last; 
     this.last = this.ms; 

     /** Calculate floating-point delta and increment time member */ 
     this.delta = 0.001 * this.dt; 
     this.time += this.delta; 

     /** Calculate private temp variables for fps calculation */ 
     if (this.frameCounter) { 
      timeToUpdate += this.dt; 
      framesToUpdate++; 
      if (timeToUpdate > 1000) { 
       this.fps = Math.round((framesToUpdate * 1000)/timeToUpdate); 
       framesToUpdate = 0; 
       timeToUpdate = 0; 
      } 
     } 
    } 
} 

如果你使用这个对象,那么所有你需要做在你的初始化函数创建一个新的时钟对象,像这样clock = new Clock();。然后在每个动画调用中调用clock.tick()。然后,您可以访问成员clock.deltaclock.time,它们会以秒为单位给出delta和time作为浮点值。 clock.dtclock.ms会给你相同的毫秒整数。您也可以使用clock.fps访问fps,或者通过设置clock.frameCounter = false来禁用它。

+0

嗯,我尝试了你的建议,它仍然呈现相同的问题。我认为我的游戏循环逻辑出于某种原因是不正确的,我尝试的一切似乎都以同样的方式作出反应。我拿了别人的代码,并且能够在我的电脑上制作一个流畅的动画,所以我可能不得不将我的游戏重新加入主循环,看看会发生什么。再次感谢您的帮助。我希望有一个全部用于JavaScript的游戏循环逻辑。 – Quantastical 2012-08-06 12:39:29

+0

这听起来像是一个好主意,你在这个应用程序中的结构执行得很好,但对于你到目前为止看起来确实很复杂。我将从3个函数init,animate和render开始。尽可能以最简单的方式使其运行良好,并在您为游戏增加复杂性时建立抽象。到目前为止,所有不同的文件和类似乎有点矫枉过正。尽管如此,它确实看起来不错。一些小东西可能不正确,而且很难将程序流尽可能简单地视觉化。 – 2012-08-06 19:26:52

+0

单挑:我简化了逻辑并更新了我的问题。这个答案可能不再相关。 – Quantastical 2012-08-07 03:36:47

1

使用three.js时钟平滑了我的动画。我强烈推荐它。其他好的代码也在那里。

+0

'clock.js'使用'Date.now()'来实现它。我想知道它如何比OP中的代码更流畅。 – tigrou 2015-05-14 16:31:10