- Home /
Ensure Mecanim registers Boolean before turning off?
I use booleans to trigger attack/death animations in Mecanim, setting the "die" boolean to true, and then in the next frame, in the update, setting it back to false.
In most cases, it runs just fine.
However, if the object dies too fast (or something -- usually when they're hit multiple times quickly), the animation never actually starts. The boolean is set to true, then to false, but somehow the animation doesn't start before it's set back to false, even though that happens on the next update cycle.
Is there a way to ensure that the animation boolean isn't set to false until after it's started playing the proper animation?
Thanks!
BTW, I've somewhat "solved" this, only by making sure 10 FixedUpdate rounds have gone by before changing the die boolean to false:
if (lastAnimation != null && lastAnimation == "die")
{
deadDelay += 1;
if (deadDelay >= 10)
{
charAnimator.SetBool(lastAnimation, false); // Avoid a constant loop
lastAnimation = null;
}
}
Answer by infinitypbr · Sep 30, 2013 at 06:02 AM
Ok, I think I found the solution. So far it's working 100%. I noticed during more testing that some of the attack animations weren't playing while the attack code (ray casts etc) was. They seem to all be working now too.
First, I added these variables:
var stateIdDie : int; // The Hash of the State ID for this Animation
var stateIdAttack1 : int; // The Hash of the State ID for this Animation
var stateIdAttack2 : int; // The Hash of the State ID for this Animation
var stateIdAttack3 : int; // The Hash of the State ID for this Animation
var stateIdMagic1 : int; // The Hash of the State ID for this Animation
var stateIdMagic2 : int; // The Hash of the State ID for this Animation
var stateIdMagic3 : int; // The Hash of the State ID for this Animation
private var lastAnimation : String; // To keep it from looping in the Animator
private var lastHash : int; // To keep it from looping in the Animator
Next, I populated them upon Start()
stateIdDie = charAnimator.StringToHash("Base Layer.Die");
stateIdAttack1 = charAnimator.StringToHash("Upper Body.Attack1");
stateIdAttack2 = charAnimator.StringToHash("Upper Body.Attack2");
stateIdAttack3 = charAnimator.StringToHash("Upper Body.Attack3");
stateIdMagic1 = charAnimator.StringToHash("Upper Body.Magic1");
stateIdMagic2 = charAnimator.StringToHash("Upper Body.Magic2");
stateIdMagic3 = charAnimator.StringToHash("Upper Body.Magic3");
When I set the bool to true for various actions, I also set the lastAnimation and lastHash...your version will differ most likely
if (lastAnimation == "attack1")
lastHash = stateIdAttack1;
if (lastAnimation == "attack2")
lastHash = stateIdAttack2;
if (lastAnimation == "attack3")
lastHash = stateIdAttack3;
if (lastAnimation == "magic1")
lastHash = stateIdMagic1;
if (lastAnimation == "magic2")
lastHash = stateIdMagic2;
if (lastAnimation == "magic3")
lastHash = stateIdMagic3;
Then in Update(), to turn it off, I use:
if(charAnimator.IsInTransition(0) && charAnimator.GetNextAnimatorStateInfo(0).nameHash == lastHash)
charAnimator.SetBool(lastAnimation, false);
It seems that the state -- basically which animation is playing -- is held in a numerical Hash. Once you know that hash, you can query to see if the hash for the next state is the same as the one you just set. If it is, set the bool to false. This way, if the animation hasn't started playing yet, the bool will not be set to false.
Answer by TonyLi · Sep 29, 2013 at 08:34 PM
What about kicking off a coroutine that checks and fixes the bool if necessary? Better than checking every Update().
Of, if you're using the Event System for Mecanim, just set the event to critical to guarantee that it occurs.
I think the problem I'm facing is that I don't know how to check to make sure that the Animator has registered and acted upon the die = true boolean before turning it off.
It seems that in these "fast death" cases, the boolean is turned on, then off, before the Animator processes it's next frame, if that makes sense.
So I'm not sure how a coroutine would be any different, since I'm only able to ensure that the boolean is true, but not that the animation has actually started playing.
I've changed my code to this:
if (charAnimator.GetBool("die"))
charAnimator.SetBool("die", false);
if (charAnimator.GetBool("attack1"))
charAnimator.SetBool("attack1", false);
if (charAnimator.GetBool("attack2"))
charAnimator.SetBool("attack2", false);
if (charAnimator.GetBool("attack3"))
charAnimator.SetBool("attack3", false);
if (charAnimator.GetBool("magic1"))
charAnimator.SetBool("magic1", false);
if (charAnimator.GetBool("magic2"))
charAnimator.SetBool("magic2", false);
if (charAnimator.GetBool("magic3"))
charAnimator.SetBool("magic3", false);
That's much more specific: It won't turn the boolean to false unless it's specifically already set true. However, I still get the issues: characters "die", but never perform the death animation, so simply stop moving, standing up.
EDIT: Also, this only happens with the "die" animation -- none of the others have this problem. The only difference is that the "die" animation is connected from Any State, while the others are connected from "Idle"
EDIT 2: When it doesn't work right, when the enemy is left dead standing up, the base layer is stuck in "idle" but the upper body layer is running "die" as it's supposed to. So somehow only the upper body registered.
Below is the Animator setup -- maybe I'm setting it up incorrectly?

EDIT 3: I've now set the weight of the upper body to 0 at the same time that I set die to true. That, so far, seems to have fixed the problem, somewhat. It still happens, though not as much.
Your answer