I've simplified my game loop to just a box moving across the screen, Click Here. For some reason, the box doesn't seem to move smoothly. I've made a video of it here.
The game loop is called like so:
var game = function( ) {
var now = Date.now( );
var delta = now - then;
update( delta / 1000 );
draw( );
then = now;
};
setInterval( game, 1000 / 50 );
I have tried separating the draw
calls from the main game loop and put them in requestAnimationFrame
, but the problem persists. I've looked at a bunch of tutorials that seem to run smoothly. I've even tried using a fixed time-step game loop, but that just made my game run unmanageably fast.
How can I improve upon the above logic, perhaps utilizing the requestAnimationFrame
and maintaining deltaTime
for the update
calls.
I've simplified my game loop to just a box moving across the screen, Click Here. For some reason, the box doesn't seem to move smoothly. I've made a video of it here.
The game loop is called like so:
var game = function( ) {
var now = Date.now( );
var delta = now - then;
update( delta / 1000 );
draw( );
then = now;
};
setInterval( game, 1000 / 50 );
I have tried separating the draw
calls from the main game loop and put them in requestAnimationFrame
, but the problem persists. I've looked at a bunch of tutorials that seem to run smoothly. I've even tried using a fixed time-step game loop, but that just made my game run unmanageably fast.
How can I improve upon the above logic, perhaps utilizing the requestAnimationFrame
and maintaining deltaTime
for the update
calls.
-
I didn't see that at all, it also said
59
all the time. Is that the fps? – Esailija Commented Aug 5, 2012 at 20:38 - Hmmm, yes 59 is my attempt at displaying the number of updates per second. On my Mac in both Safari and Chrome, I am seeing the paddles and ball jump forward a little bit, instead of moving smoothly. I guess I should check it on some other puters. – jeffjenx Commented Aug 5, 2012 at 20:44
- I guess the ball is a bit jerky if I look really closely... this is because in some frames, the ball moves more than 1px at a time. – Esailija Commented Aug 5, 2012 at 20:45
-
Correct. Is there a way to correct this behavior? I thought that by having my updates based on
deltaTime
(time diff. between update cycles) that would smooth things out. – jeffjenx Commented Aug 5, 2012 at 20:48 - I don't seem to notice that behavior on my puter, but that is most likely because the FPS more or less constant. However, this is most likely a biproduct of the fact that you are drawing too much, make a separate canvas that you don't update that has the background on it or make yourself a system that only draws dirty items (stuff that has changed position/scale/rotation/color etc) – Radu Chivu Commented Aug 5, 2012 at 20:57
2 Answers
Reset to default 4I believe when using canvas your position variables should be integer values because they represent pixels and floating point values do not make sense. If you open up the console and enter in sceneManager.currentScene.GameplayLayer.ball.position.x
then you get back a really long decimal. I think the ment on the OP that suggests that sometimes the ball is moving 2px instead of a 1px may be on to something. When you update your position you end up with a floating point value.
I believe it sometimes rounds up to the next highest pixel position, sometimes down. I would try taking the floor or ceiling like so:
this.position.x += Math.floor(this.speed * 100 * deltaTime * Math.cos(directionInRadians));
this.position.y += Math.floor(this.speed * 100 * deltaTime * Math.sin(directionInRadians));
I would make both of these changes and see how it behaves.
EDIT: Since you edited your question to simplify the logic. I can suggest something to try, which is to use this Clock object I created which I use all the time. It gives me smooth animation and it's rather simple. It is based off of the clock that Three.JS uses so you might want to check that out as well. Even if you want to use your own code you can at least try this ready-made solution and see if it gives you the same results. It seems to work just fine for me. Also, you tried using the shim so your call in the game function should be 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 remended that
tick() is called from a callback loop using requestAnimationFrame
Learn more: http://paulirish./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;
}
}
}
}
If you use this object then all you need to do is create a new clock object in your initialization function like so clock = new Clock();
. Then call clock.tick()
in each animation call. You can then access the members clock.delta
and clock.time
which will give you the delta and time as a floating point value in seconds. clock.dt
and clock.ms
will give you the same as integer in millseconds. You can also access the fps using clock.fps
or disable it by setting clock.frameCounter = false
.
Using three.js
clock smoothed up my animation. I highly remend it. Tons of other good code in there as well.