Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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
  display_frame(frame[current_frame_index])
}

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?

Thanks!

share|improve this question

3 Answers 3

up vote 3 down vote accepted

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];
        display_frame(frame[frame_index]);
    }
}
share|improve this answer
1  
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. –  Chris Subagio May 22 '11 at 20:16
    
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. –  GloryFish May 25 '11 at 18:24
    
@Chris: tanx for comment and i've applied your change. –  Ali.S May 25 '11 at 18:29
    
@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 –  Ali.S May 25 '11 at 18:32
    
@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. –  Chris Subagio Jun 3 '11 at 7:23

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
etc

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

share|improve this answer

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.

update(time)
{
    frames // an array of animation frames
    fFrameLength = 0;
    foreach(frame in frames)
    {
        fFrameLength += frame.duration
        if ( time * animation_length < fFrameLength )
            display_frame(frame)
    }
}
share|improve this answer
    
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. –  Valkea May 21 '11 at 0:00
    
I guess that if ( time * animation_length < fFrameLength ) should fix the problem. –  Valkea May 21 '11 at 0:21
    
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. –  James May 22 '11 at 6:39
    
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. –  GloryFish May 25 '11 at 18:27
    
@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. –  James May 25 '11 at 18:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.