- Home /
Check the current frame of an animation
Hello everyone
I am having problems with this. I want to activate a boolean variable when a variable reaches a certain frame, and set it to false again after 1 second (or 0.5, something like that). But I'm having problems with yield WaitForSeconds() because not always the variable triggers. I did something like this, but the script doesnt activate the variable at the same moment everytime and it doesn't even activate sometimes (In javaScript):
If(Input.GetButtonDown("Fire1")){
yield WaitForSeconds(0.16); //0.16 it's moreless the time I've calculated
attacking = true;
yield WaitForSeconds(0.5);
attacking = false;
}
What can I do?
Well it doesn't matter that much. I managed to do it with yield WaitForSeconds(), but i'm interested yet in how can I do that
Answer by Dreamora · Jul 29, 2011 at 10:09 AM
You can get a frame from an animation as animations have no frames, only animation time.
If you want to change something on an explicit frame, the way to go are animation events that you can hook up to fire at a specific frame :)
Well, I've been trying it, but I can't, it seems that the animation clips I created with blender are "Read Only" and I can't crete the animation event
They are generally always read only. But you can just clone it and apply it to the copy and use that copy for example :)
the reason for the read only is that you can update your mesh and nothing breaks. if you could apply it to the animation, all the events would just blow up and go away on each mesh reimport
Answer by nickpedalino · Apr 15, 2016 at 08:16 PM
I needed to get the frame number to reference an array of positions on the animated sprite based off the animation frame.
It's worth noting that in the vast majority of cases, @Dreamora 's answer is sufficient.
For those who really, really need the current frame, here's a line of code that'll do that!
animationIndex = ((int)(mAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime * (mNumAnimationFrames))) % mNumAnimationFrames;
I had to do the modulo calculation at the end because for some reason normalizedTime was not returning a normalized value, and kept incrementing my index indefinitely.
Normalised time will go >1 for each loop of the animation. So 2.5 is two and half times played.
I should add, as Dreamora said, frames don't really exist at runtime as the endresult is always interpolated between two frames. So by casting the time to an int you effectively returned the lower frame index of the current position. However keep in $$anonymous$$d if the time is close to the next frame the interpolated result will almost match the "next" frame but you're getting the last frame.
Also you should multiply by (frameCount - 1) ins$$anonymous$$d or you will get the 10th frame (index 9) when you actually reached frame 9 (index 8). When multiplying by 10 you actually split the timeline into 11 points. See this example of an animation with 10 frames:
time: 0.0 0.111 0.222 0.333 0.444 0.555 0.666 0.777 0.888 1.0
| | | | | | | | | |
frame: 1 2 3 4 5 6 7 8 9 10
index: 0 1 2 3 4 5 6 7 8 9
do$$anonymous$$ant: | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |
If the normalized time is "0.44333":
float nTime = 0.44333f;
int frames = 10;
int index = ((int)(nTime * (frames-1)))%(frames-1); // == 3
However since the time is almost at frame 4, what you actually see is the state of frame 4 because the actual time once multiplied by 9 is "3.99" so almost at frame 4
"index" actually represents the lower frame index and "index+1" the upper index. The actual state of the animation is somewhere in between those two frames. To get a linear lerp value for that you can do:
float f = (nTime * (frames-1))%(frames-1); // == 3.99
int lowerIndex = $$anonymous$$athf.FloorToInt(f);
int upperIndex = lowerIndex + 1;
float t = f - lowerIndex;
If you just want to pick the frame that currently has the greatest effect, you just want to round "f" ins$$anonymous$$d of "flooring" it.
int do$$anonymous$$antFrame = $$anonymous$$athf.RoundToInt((nTime * (frames-1))%(frames-1)); // == 4
"do$$anonymous$$antFrame" will step to the next frame when we crossed the 0.5 mark between two frames. The first and last frame are "half" frames as the first starts at 0 and the last ends at 1.
ps: I wrote those examples from scratch. If you find any mistakes please let me know ^^.
Your answer
Follow this Question
Related Questions
Call a function dependent on frame of animation? 2 Answers
picking up and using animated items/weapons. 0 Answers
How to play animation with one click 1 Answer
why does Coroutine 'yield return 0' sometimes take a lot of frames before it continues 1 Answer
How can I make a variable false for a period of time? 3 Answers