Determining the time length of an animation before it plays

Started by Dave Gilbert, Mon 11/12/2023 14:07:15

Previous topic - Next topic

Dave Gilbert

Hi all! Basically as the subject says. Is there a way to calculate the length of time a character animation will take to play (based on the character's animation speed, the speed you play the animation, delays on frames, the game's framerate, etc) before you play it? Preferably in seconds or milliseconds?

Basically what I want to do is to run a tween that finishes exactly when the character's animation stops. The only way to do that is to determine how long the animation takes to play.

Any light-shedding appreciated!

-Dave

Crimson Wizard

I suppose that may be possible.

Animation is played frame by frame, advancing a frame when the delay runs out. Frame delay is a sum (addition) of character's animation speed property (which is, counter-intuitively, a "delay"), and individual frame's delay.
The frame's delay is measured in "game updates" (aka "game frames", aka "game loops", aka "game ticks").
The real duration of a "game frame" is 1/GameSpeed seconds.

So, suppose you have N frames in animation.
The duration of full animation in game frames would be a
Code: ags
    DUR_gf = SUM(each frame delay) + (animation speed * N)
And the duration in real time would be
Code: ags
    DUR_s = DUR_gf / GameSpeed

Dave Gilbert

Thanks CW! Just a few clarifications.

So for the first one, "SUM" is calculated by taking all the delays of each frame in the animation and adding them up?

And for "(animation speed * N)", which animation speed does this refer to? The speed you set for the character? Or the "delay" you set when you type in the Character.Animate command?

Crimson Wizard

#3
Quote from: Dave Gilbert on Mon 11/12/2023 14:23:01So for the first one, "SUM" is calculated by taking all the delays of each frame in the animation and adding them up?

That is correct.

Quote from: Dave Gilbert on Mon 11/12/2023 14:23:01And for "(animation speed * N)", which animation speed does this refer to? The speed you set for the character? Or the "delay" you set when you type in the Character.Animate command?

I had some strange memory twist, and forgot that character's property only refers to specific animations (walking, speaking).
So, the animation delay is a delay arg you pass into Animate.
EDIT: sorry I need to double check this, I will be back :)
EDIT2: alright, I confirmed, and Character's AnimationSpeed is basically "Walking Animation Speed" only. In the past it was also affecting Idle animation, but no more since 3.6.0.

eri0o

I think the .Animate topic in the manual has a few details

https://adventuregamestudio.github.io/ags-manual/Character.html#characteranimate

https://adventuregamestudio.github.io/ags-manual/Object.html#objectanimate

It looks like with View, animate_speed, loop, direction and starting frame, it should be possible to create a function that takes these and figure it out the delay in ticks from these.


Dave Gilbert

Quote from: Crimson Wizard on Mon 11/12/2023 14:27:27EDIT2: alright, I confirmed, and Character's AnimationSpeed is basically "Walking Animation Speed" only. In the past it was also affecting Idle animation, but no more since 3.6.0.

 :shocked:

I could have sworn the character's animation speed effected all of their animations, and not just walking. It seems like I was wrong for over 20 years!

Anyway, thanks. I will fiddle.

-Dave

Matti

That's good to know, and strange to hear. I also thought that every animation was effected by that.

Maybe the character's animation speed should be renamed to character's walking animation delay  ;-D

Laura Hunt

Quote from: Dave Gilbert on Mon 11/12/2023 14:07:15Basically what I want to do is to run a tween that finishes exactly when the character's animation stops. The only way to do that is to determine how long the animation takes to play.

Or just check in repeatedly execute if the character has stopped animating, and trigger the tween then? It's what I always do when I want to chain together non-blocking animations, for example.

Dave Gilbert

Not sure how that would work, since I want the tween to finish when the animation stops, not for the tween to begin. I have an object that starts to move when the character beings her animation, and I want it to naturally come to a stop exactly when the character finishes her animation. Unless I'm misunderstanding what you mean.

Laura Hunt

Quote from: Dave Gilbert on Mon 11/12/2023 19:37:48Not sure how that would work, since I want the tween to finish when the animation stops, not for the tween to begin.

Ah, I totally misread this and thought you wanted the tween to start when the animation stops. I was surprised that the answer was so convoluted, but this explains it :-D

Khris

I tested this with a basic animation and it seems to work:
Code: ags
// header
import int AnimateFrames(this Character*, int loop, int delay, RepeatStyle repeatStyle = eOnce, BlockingStyle blockingStyle = eBlock, Direction direction = eForwards, int frame = 0, int volume = 100);

// main
int AnimateFrames(this Character*, int loop, int delay, RepeatStyle repeatStyle, BlockingStyle blockingStyle, Direction direction, int frame, int volume) { 
  this.Animate(loop, delay, repeatStyle, blockingStyle, direction, frame, volume);
  int frames = 0;
  // TODO: handle eBackwards
  for (int i = frame; i < Game.GetFrameCountForLoop(this.View, loop); i++) {
    ViewFrame* vf = Game.GetViewFrame(this.View, loop, i);
    frames += delay + vf.Speed + 1;
  }
  return frames;
}

Use like:
Code: ags
  player.LockView(VIEW2);
  int frames = player.AnimateFrames(0, 10, eOnce, eNoBlock, eForwards);

If you need milliseconds, use
Code: ags
  int ms = (frames * 1000) / GetGameSpeed();


(Note: this only makes sense with eOnce and eNoBlock so one could skip these but I simply copied all Animate parameters)

Dave Gilbert

Thanks Khris! One question. It looks like your function plays the animation and THEN counts the frames/ms length. Is there a reason why you played the animation beforehand?

Dave Gilbert

#12
Thanks Khris! One question. It looks like your function plays the animation and THEN counts the frames/ms length. Is there a reason why you played the animation beforehand?

edit: I tried it out myself and it appears that you don't need to play the animation beforehand! The method worked.

Before I had this animation of a little girl jumping off a table. The fact that her shadow kept jumping around bothered the heck out of me. Such a tiny trivial thing, but shadow jumping happens all over the game so I wondered if there was an easy way to fix it. Now I can!  Thanks for the help, everyone!



edit2: Weird. I went to edit but it double-posted instead. Sorry about that!

Khris

Quote from: Dave Gilbert on Tue 12/12/2023 13:36:38Thanks Khris! One question. It looks like your function plays the animation and THEN counts the frames/ms length. Is there a reason why you played the animation beforehand?

This basically happened on accident, I did the easy thing first (calling the actual Animate command) and later noticed I can leave it up there because it doesn't make a difference :)
The approach changes if you have a blocking animation; in that case you have to move the Animate call outside the counting function anyway.

Dave Gilbert

Yeah, if the animation is non-blocking it saves me from having to type a second, almost identical line, which could be useful. But if the animation is blocking than it's more of a hindrance than a help. Easy enough to edit. Thanks for the help!

SMF spam blocked by CleanTalk