带有游戏循环的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(游戏)代码>
如果使用此对象,则只需在初始化函数中创建一个新的时钟对象,如soclock=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;
}
}
}
}