- Home /
Can one Animation Event be used for a timespan (multiple frames)?
I have watched this brilliant tutorial about animation events in Unity and I have to say I am very impressed with their power and ease of use.
In my case however, I need to be able to have a function check specific conditions starting from a specific frame and ending at a specific frame. For example, using a similar case to the video above, if I have an attack animation 20 frames long, and I would like my function to check a condition from frames 12-18 only, can this be achieved using animation events only? I realise the same event could be created for each of these frames but then if I have a damage function for example, this function would be applying the damage multiple times (once in every frame it is called) which is not the desired effect. At the moment, the only way I can see this working is using a boolean also. Is there another way?
Answer by Bunny83 · Apr 04, 2012 at 05:50 PM
Animations are timebased in Unity. Animation consist of keyframes that are interpolated. So an animation ia always inbetween two keyframes. So frames doesn't exist in terms of animations.
What you can do is create one animation event that sets a variable "true" and another one that reverts it to false. That way you have a variable that can be used in update. It will be true as long as the animation is in between your two animationevents.
edit
I guess you want to check for "hits" only between sepcific keyframes. As already said Keyframes are irrelevant for Unity. They are just used to interpolate the actual values. Animations and of course animation events are timebased. For more information see AnimationEvents.
I suggested to use a boolean to signal that the animation is in between the desired keyframes / timespan. This variable can be used as an additional condition. I guess you use a sword with a collider and use it as trigger (At least this is how we have done our collision so far).
In the OnTriggerEnter callback you can check if the condition is true. So any collisions that happens outside of the timespan will be ignored.
//C#
//[...]
public bool isAttacking; // set / reset by animation events
void OnTriggerEnter(Collider aOther)
{
if (isAttacking)
{
// do damage to aOther
}
}
// ********************************
// UnityScript (Unitys Javascript)
var isAttacking : boolean; // set / reset by animation events
function OnTriggerEnter(aOther : Collider)
{
if (isAttacking)
{
// do damage to aOther
}
}
Just as a final hint: We used a quite similar way for our hack & slash game. We didn't used animation events, but also a timespan within the animation. The big problem with colliders / triggers and fast animations is that it will often miss a collision due to a low framerate. We tried a lot optimisations but nothing was satisfying. Since animations are sampled at the current time and the time advances in relation to the current FPS the actual movement will look different each time you play the animation. If a movement is really fast it could even happen that it completely skips the fast part (if the deltaTime is too big).
Our project has been abandoned since it was a student project so we stopped searching for a solution. I can't really suggest a specific method since that depends on how your attack animations look like. If our project is resurrected the other day we thought about using non-animated colliders that just describe the trajectory of the weapon and apply damage to what ever is in this area at a specific time.
It's pretty obvious this question is talking about character animation clips not tweening from one key frame (and definitely not keyrames) to another. When character animations are brought into Unity, the fbx conversion will make all frames into keys, depending on which 3D package they're viewed/played in, so the animation does not only occur between key frames.
In Unity's animation view third party animations often don't even show any keys at all so what you're saying makes no sense and is completely irrelevant. If you'd actually bothered to read the question properly you would've realized it asks a way besides using a boolean variable in which case the answer is no. Judging by the question, you just told him probably everything he already knows and confused the hell out of him with spelling that's all over the place and rubbish like 'frames don't exist in animations'. Wtf?
Thank you for the suggestion Bunny83. If I use a boolean or true/false variable however, and as in my example have a function which does damage to an NPC when this variable is set to true (during the frames/key frames 12-18 only for example) wouldn't that mean that the attack animation damage is being dealt in every one of these frames? The desired effect here is to be able to check whether the NPC should have damage applied to it anytime during frames 12-18 however only deal this damage once. If this is unclear let me elaborate further.
Consider a sword swing or simple physical punch even; in between the intial wind up and the post attack recovery, there are several frames in which the animation can "hit" the NPC but at the same time it is still only one physical motion and therefore should not be "damaging" the NPC in every frame it "hits", unless it where some sort of elemental attack (which it is not). Is this clearer now?
@UnityDeveloper99: I was actually talking about character animations as well. It seems you don't understand how Unitys Animation component works. Every AnimationClip is is composed of AnimationCurves. Each AnimationCurve consists of two or more $$anonymous$$eyframes.
Those AnimationCurves are sampled each (visual) frame during the update process. This sampling happens at the current animation time and will almost always fall between two keyframes.
AnimationEvents are, as the name my suggest, events that are fired at a specific animation time. Events are always actions. To represent a timespan, like the OP wants, you can use a boolean variable which get set at the beginning of this timespan and reset at the end.
It seems the OP wants to consider collision events only within a specific timespan. The boolean can be used as an additional condition in OnCollisionEnter for example.
Now i just ask myself what's the point of your comment.
@Bunny83 Every 3d program worth mentioning uses animation curves, that is a given. As you confirmed in your now actually helpful answer, when using character animation these curves are not always visible in Unity's Animation View which was exactly my point. Also, if you're gonna complain about comments being hard to read in a perfectly well formatted script, I can complain about your spelling being hard to read can I not? This guy has just posted his first two questions on UA and, prior to your edited answer, you had spent 2 thirds of your posts griping about things not even relevant to his question. What is the point of that, and how is that helpful? They are question which many beginners ask and will help others in the Unity community.
@$$anonymous$$Gurran The only way you could do what you want as far as I can see is by using two booleans:
1) First to flag the animation timespan, as suggested above
2) Second to flag whether damage has already been caused in that timespan(both should be false by default).
You would also have to implement a way to reset the "has damage already occurred in this timespan" boolean so that it is set back to false for next time around, possibly in an animation event after the "damaging" frames. This way your specified animation timespan will be checked for the relevant damage conditions including if damage has already been applied. If either condition is not met damage won't happen. This way you should be able to receive damage anytime during the specified timespan BUT only once. Does that help?