Reputation: 189
I am creating an animation using javascript and canvas. How can I allow the user to specify the order in which to display the frames and change the speed at which they are displayed. This is what I have so far
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
(function () {
var coin,
coinImage,
canvas;
function gameLoop () {
window.requestAnimationFrame(gameLoop);
coin.update();
coin.render();
}
function sprite (options) {
var that = {},
frameIndex = 0,
tickCount = 0,
ticksPerFrame = options.ticksPerFrame || 0,
numberOfFrames = options.numberOfFrames || 1;
that.context = options.context;
that.width = options.width;
that.height = options.height;
that.image = options.image;
that.update = function () {
tickCount += 1;
if (tickCount > ticksPerFrame) {
tickCount = 0;
// If the current frame index is in range
if (frameIndex < numberOfFrames - 1) {
// Go to the next frame
frameIndex += 1;
} else {
frameIndex = 0;
}
}
};
that.render = function () {
// Clear the canvas
that.context.clearRect(0, 0, that.width, that.height);
// Draw the animation
that.context.drawImage(
that.image,
frameIndex * that.width / numberOfFrames,
0,
that.width / numberOfFrames,
that.height,
0,
0,
that.width / numberOfFrames,
that.height);
};
return that;
}
// Get canvas
canvas = document.getElementById("coinAnimation");
canvas.width = 500;
canvas.height = 500;
// Create sprite sheet
coinImage = new Image();
// Create sprite
coin = sprite({
context: canvas.getContext("2d"),
width: 500,
height:72,
image: coinImage,
numberOfFrames: 10,
ticksPerFrame: 4
});
// Load sprite sheet
coinImage.addEventListener("load", gameLoop);
coinImage.src = "sprite.png";
} ());
Upvotes: 2
Views: 366
Reputation: 19294
Rq : You might remove the code defining requestAnimationFrame for Browsers not supporting it since 1) setTimeout is too inaccurate and 2) a Browser supporting Canvas will moooost likely implement it, so the polyfill is enough.
To change your coin animation, you need to have a sprite update that takes a time parameter (dt, the time elapsed since last frame). So compute the time in your update loop : have it compute game time and current frame's dt (what you did for rAF can be reused here).
Then you need some way of storing the frames/frames duration data within your sprite.
You can use an array of { duration : , frame : } objects.
I personally like an array like this one : [ duration1, frameIndex1, duration2, frameIndex2, ...] (faster, and no reference issue if you copy it with slice(0). ).
Then during the update of the coin, you'll have to handle a current time position instead of a tick count, and 'eat-up' as many duration as you can with the dt you have at hand to find the next frame.
Now to come to your very question, to edit the animation, i would use a separate canvas, below your display canvas, and a bunch of buttons to changes things. i did a very simple jsbin, it looks like this :
the jsbin is here : http://jsbin.com/IjAtOxe/1/edit?js,output
Upvotes: 2