带有游戏循环的JavaScript平滑动画

带有游戏循环的JavaScript平滑动画,javascript,animation,html5-canvas,game-physics,Javascript,Animation,Html5 Canvas,Game Physics,我已经简化了我的游戏循环,使之成为一个在屏幕上移动的盒子。由于某种原因,箱子似乎移动不平稳。我犯了一个错误 游戏循环的名称如下: var game = function( ) { var now = Date.now( ); var delta = now - then; update( delta / 1000 ); draw( ); then = now; }; setInterval( game, 1000 / 50 ); 我已经尝试将dra

我已经简化了我的游戏循环,使之成为一个在屏幕上移动的盒子。由于某种原因,箱子似乎移动不平稳。我犯了一个错误

游戏循环的名称如下:

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

    update( delta / 1000 );
    draw( );

    then = now;
};

setInterval( game, 1000 / 50 );
我已经尝试将
draw
调用从主游戏循环中分离出来,并将它们放入
requestAnimationFrame
,但问题仍然存在。我看了很多教程,似乎运行得很顺利。我甚至尝试过使用a,但这只是让我的游戏运行速度无法控制


我如何改进上述逻辑,也许可以利用
requestAnimationFrame
并为
update
调用维护
deltaTime

我认为在使用canvas时,位置变量应该是整数值,因为它们代表像素,而浮点值没有意义。如果打开控制台并输入
sceneManager.currentsecene.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));
我将进行这两项更改,并查看其行为。

编辑:因为您编辑了问题以简化逻辑。我可以建议一些尝试,就是使用我创建的这个时钟对象,我一直在使用它。它给我平滑的动画,而且相当简单。它是基于的,所以您可能也想检查一下。即使您想使用自己的代码,您至少可以尝试这个现成的解决方案,看看它是否能给您相同的结果。这对我来说似乎很管用。另外,您尝试使用垫片,因此您在游戏函数中的调用应该是
requestAnimFrame(游戏)


如果使用此对象,则只需在初始化函数中创建一个新的时钟对象,如so
clock=new clock()。然后在每个动画调用中调用
clock.tick()
。然后,您可以访问成员
clock.delta
clock.time
,它们将以秒为单位将delta和时间作为浮点值
clock.dt
clock.ms
将以毫秒为单位给出与整数相同的值。您还可以使用
clock.fps
访问fps,或者通过设置
clock.frameCounter=false
来禁用fps,使用
three.js
clock平滑我的动画。我极力推荐。那里还有很多其他的好代码。

我根本没有看到,它也一直在说
59
。是fps吗?嗯,是59是我试图显示每秒更新的次数。在Safari和Chrome的Mac上,我看到球拍和球向前跳了一点,而不是平稳地移动。我想我应该在其他电脑上检查一下。如果我仔细看的话,我想球有点不稳。。。这是因为在某些帧中,球一次移动超过1px。正确。有没有办法纠正这种行为?我认为基于
deltaTime
(更新周期之间的时间差)进行更新可以使事情顺利进行。我似乎没有注意到计算机上的这种行为,但这很可能是因为FPS或多或少是恒定的。然而,这很可能是因为你画得太多,制作一个单独的画布,你不更新它的背景,或者让自己成为一个只画脏东西(改变了位置/比例/旋转/颜色等的东西)的系统。我尝试了你的建议,但仍然出现了同样的问题。我认为由于某些原因,我的游戏循环逻辑是不正确的,我尝试的每件事似乎都有相同的反应。我使用了其他人的代码,并且能够在我的计算机上制作一个平滑的动画,所以我可能不得不将我的游戏重新制作到他们的主循环中,看看会发生什么。再次感谢你的帮助。我希望JavaScript有一个全结束-全游戏循环逻辑。这听起来是个好主意,你在这个应用程序中的结构设计执行得很好,但就你目前所拥有的来说,它似乎非常复杂。我将从3个函数开始初始化、设置动画和渲染。尽可能用最简单的术语让它工作良好,并在游戏增加复杂性时建立抽象概念。到目前为止,所有不同的文件和类似乎都有点过分了。不过,对我来说,这看起来确实是一个很好的编程。有些小事情可能就是不对,而且很难想象程序流程如此简单。请注意:我已经简化了逻辑并更新了我的问题。这个答案可能不再中肯了。感谢您的持续关注。我构建了一个利用时钟类的。我一定是疯了,因为我仍然能以每秒60帧的速度看到起伏的动画。我把它降到30 FPS,它的反应也一样。我想我对JavaScript的期望可能太高了,我可能不得不安定下来。盒子以正确的速度移动,但它偶尔会有点口吃。我在大约:Chrome中的flags中打开了FPS计数器,每当动画抖动时,它就会显示山谷。嗯,对我来说,它看起来运行得非常平稳。。。我认为你所指和看到的是垃圾收集器经常清理东西造成的。。我可以问一下您正在运行的浏览器是什么,以及可能会产生影响的任何扩展吗?或者它在所有方面都是完全一样的?对我来说,这绝对是Chrome中最流畅的,但在你放弃全部Javascript之前,你可能想看看Three.JS示例,看看Canvas演示如何使用该库在你的机器上运行。它有一个出色的画布渲染器,对我来说也非常平滑。
clock.js
使用
Date.now()
实现它。我是一名医生
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;
            }
        }
    }
}