2

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";

 } ());

1 Answer 1

2

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 :

enter image description here

the jsbin is here : http://jsbin.com/IjAtOxe/1/edit?js,output

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.