Skip to content

Commit 9b585b5

Browse files
committed
[#99] [#390] Allow animation updates to skip frames
- This is important for slow devices and high-speed animations - A slow device may render at 30fps (33.333ms per frame) or slower, and animations may play at 60fps (16.6667ms per frame) or faster! - Animation frame skipping will keep animations in sync across all devices. - See also: https://groups.google.com/forum/#!msg/melonjs/mM4BdyQyNY8/ygEJUIPvDJwJ
1 parent a66e23f commit 9b585b5

2 files changed

Lines changed: 38 additions & 28 deletions

File tree

src/level/TMXTileset.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,11 @@
216216
this.animations.forEach(function (anim) {
217217
anim.dt += dt;
218218
duration = anim.cur.duration;
219-
if (anim.dt >= duration) {
219+
while (anim.dt >= duration) {
220220
anim.dt -= duration;
221221
anim.idx = (anim.idx + 1) % anim.frames.length;
222222
anim.cur = anim.frames[anim.idx];
223+
duration = anim.cur.duration;
223224
result = true;
224225
}
225226
});

src/renderable/animationsheet.js

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
// default animation sequence
6060
this.current = null;
6161

62+
// animation frame delta
63+
this.dt = 0;
64+
6265
// default animation speed (ms)
6366
this.animationspeed = 100;
6467

@@ -115,8 +118,7 @@
115118
frames : [],
116119
idx : 0,
117120
length : 0,
118-
animationspeed: animationspeed || this.animationspeed,
119-
nextFrame : 0
121+
animationspeed: animationspeed || this.animationspeed
120122
};
121123

122124
if (index == null) {
@@ -203,7 +205,6 @@
203205
this.current = this.anim[name];
204206
this.resetAnim = resetAnim || null;
205207
this.setAnimationFrame(this.current.idx); // or 0 ?
206-
this.current.nextFrame = this.current.animationspeed;
207208
} else {
208209
throw new me.Renderable.Error("animation id '" + name + "' not defined");
209210
}
@@ -277,35 +278,43 @@
277278
* @param {Number} dt time since the last update in milliseconds.
278279
*/
279280
update : function (dt) {
280-
// update animation if necessary
281-
if (!this.animationpause && this.current.length > 1) {
282-
this.current.nextFrame -= dt;
283-
if (this.current.nextFrame <= 0) {
284-
this.setAnimationFrame(++this.current.idx);
281+
// Update animation if necessary
282+
if (this.animationpause || this.current.length <= 1) {
283+
return this._super(me.Sprite, "update", [ dt ]);
284+
}
285+
286+
var duration = 0,
287+
result = false;
288+
289+
this.dt += dt;
290+
duration = this.getAnimationFrameObjectByIndex(this.current.idx).delay;
291+
while (this.dt >= duration) {
292+
result = true;
293+
this.dt -= duration;
294+
this.setAnimationFrame(this.current.idx + 1);
285295

286-
// switch animation if we reach the end of the strip
287-
// and a callback is defined
288-
if (this.current.idx === 0 && this.resetAnim) {
289-
// if string, change to the corresponding animation
290-
if (typeof this.resetAnim === "string") {
291-
this.setCurrentAnimation(this.resetAnim);
292-
}
293-
// if function (callback) call it
294-
else if (typeof this.resetAnim === "function" &&
295-
this.resetAnim() === false) {
296-
this.current.idx = this.current.length - 1;
297-
this.setAnimationFrame(this.current.idx);
298-
this._super(me.Sprite, "update", [dt]);
299-
return false;
300-
}
296+
// Switch animation if we reach the end of the strip and a callback is defined
297+
if (this.current.idx === 0 && this.resetAnim) {
298+
// If string, change to the corresponding animation
299+
if (typeof this.resetAnim === "string") {
300+
this.setCurrentAnimation(this.resetAnim);
301301
}
302+
// Otherwise is must be callable
303+
else if (this.resetAnim() === false) {
304+
// Reset to last frame
305+
this.setAnimationFrame(this.current.length - 1);
302306

303-
// set next frame timestamp
304-
this.current.nextFrame = this.getAnimationFrameObjectByIndex(this.current.idx).delay;
305-
return this._super(me.Sprite, "update", [dt]) || true;
307+
// Bail early without skipping any more frames.
308+
this.dt %= duration;
309+
break;
310+
}
306311
}
312+
313+
// Get next frame duration
314+
duration = this.getAnimationFrameObjectByIndex(this.current.idx).delay;
307315
}
308-
return this._super(me.Sprite, "update", [dt]);
316+
317+
return this._super(me.Sprite, "update", [ dt ]) || result;
309318
}
310319
});
311320
})();

0 commit comments

Comments
 (0)