I have an array of sprites that are displayed in-order to make an animation. There is code in an update loop that has access to a value 'time' indicating how far along the animation is. Time is a float between 0 and 1 inclusive. It uses this value to calculate which frame to display.

update(time) {
  frames // An array of animation frames
  current_frame_index = time / animation_length

This works if you assume that each frame is displayed for the same amount of time.

I would like to enhance this by allowing frames to have arbitrarily defined durations. So if I have a set of frames and durations:

name           duration

frame_one      0.2
frame_two      1.1
frame_three    1.0
frame_four     0.75
frame_five     1.4

and a value indicating the animation's progress, how can I determine which frame to display?



3 Answers 3


though james answer is right you can also get to where you want using my implementation

void update(float dt)
    nextframe -= dt;
    while (nextframe < 0)
        nextframe += frametime[frame_index];
  • 1
    \$\begingroup\$ To expand on what Gajet wrote there, what he's proposing is that you keep track of two values: the current frame index and the time remaining until the next frame should be displayed. Each frame, you need to decrement the time remaining, and should that drop beneath zero, you increment your frame index by one and append the new time to next frame. The only thing missing is handling the case where enough time has passed to advance more than one frame. if(nextframe<0) should be while(nextframe<0) to deal with that. \$\endgroup\$ Commented May 22, 2011 at 20:16
  • \$\begingroup\$ That would work if the update() method receives a dt value. However, the value this one receives is a float from 0 to 1 indicating the animation's progress e.g. if the animation length is eight seconds, and we are four seconds in, update(time) will be called with a value of 0.5 for time. \$\endgroup\$
    – GloryFish
    Commented May 25, 2011 at 18:24
  • \$\begingroup\$ @Chris: tanx for comment and i've applied your change. \$\endgroup\$
    – Ali1S232
    Commented May 25, 2011 at 18:29
  • \$\begingroup\$ @glory fish: if you receive the progress your animation made so far then you can change frame every time input is grater than 1 or if your problem is your class works with some static frame time you can always check if dt*staticFrameTime >= currentFrameTime \$\endgroup\$
    – Ali1S232
    Commented May 25, 2011 at 18:32
  • \$\begingroup\$ @gajet Ahh, in that case your function is effectively random access, which means you'll have to search for your frame. Best thing to do is convert your time deltas in the source array into timestamps (by summing the lengths of all the keys before it), and then conduct a binary search to find the key at the given time. To deal with the time format, you can either multiply up the incoming 0-1 by the animation duration on the way into the function, or normalize the timestamps ahead of time. \$\endgroup\$ Commented Jun 3, 2011 at 7:23

While probably not that optimized, this would move to the next frame when the time value was beyond the sum of the durations of each frame.

    frames // an array of animation frames
    fFrameLength = 0;
    foreach(frame in frames)
        fFrameLength += frame.duration
        if ( time * animation_length < fFrameLength )
  • \$\begingroup\$ hum time is supposed to be a float comprised between 0 and 1, whereas the total of durations (fFrameLength in your example) is not supposed to be comprised between 0 and 1 from what I understood. Thus your script need to be slightly modified. \$\endgroup\$
    – Valkea
    Commented May 21, 2011 at 0:00
  • \$\begingroup\$ I guess that if ( time * animation_length < fFrameLength ) should fix the problem. \$\endgroup\$
    – Valkea
    Commented May 21, 2011 at 0:21
  • \$\begingroup\$ Adjusted based on this info. I just missed it some how, even reading it twice after reading the comments I missed that the time float is a percentile of the animations position. \$\endgroup\$
    – James
    Commented May 22, 2011 at 6:39
  • \$\begingroup\$ Yeah it's an unusual arrangement. Specifically I am attempting to enhance cocos2d's CCActionInterval to support heterogeneous frame durations. I am considering not trying to implement it as an interval action and instead using a standard non-sequenceable action wich would give the update method a more typical dt value and would make everything a lot simpler. \$\endgroup\$
    – GloryFish
    Commented May 25, 2011 at 18:27
  • \$\begingroup\$ @GloryFish I think this would be a potential trade off you would want to do some benchmarking around. You would save some math overhead doing this but I am not sure if the interval actions vs non-sequence-able actions change would end up eating any benefits.. Of course, ease in programming is also a consideration to keep in mind ;) PS: I actually up-voted Gajet's answer as it looked more efficient. \$\endgroup\$
    – James
    Commented May 25, 2011 at 18:47

Usually what I do in these kinds of situations is basically do what you do in the first loop, but insert an abstraction between "frame number" and "texture asset" (or UVs, if you will).

Basically, change frames[current_frame_index] to do a lookup in a table that you define for a given animation. You can set up a data structure that still works in "frames", but maybe with a higher frame rate to give you more precision.

A simple example would be something like this:

animation_frame | texture_index
0               | 0
1-8             | 1
9-12            | 2

You can convert that to a list so you can do a lookup by animation frame index into texture index.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .