- Home /
moving gameobject from state machine behaviour/different code result from inside OnStateExit()
Hello! I'm having trouble with a state machine behaviour, so far I have the following function:
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Instantiate(parSys, new Vector3(-0.038f, 0.05f, 0.694f), Quaternion.identity);
newPos = new Vector3(Random.Range(-2f, 2f), 0.05f, Random.Range(-2f, 2f));
objectParent.transform.position = newPos;
objectModel.transform.position = newPos;
}
My objective is to instantiate a particle system at the position of a game object , then teleport that gameobject to a random position, both when an animation clip has run through. The function does instantiate the particle system, it doesn't teleport the GameObject though. Strange thing is: when I put the same code into a function in a monobehaviour, it does wat I want it to. I also tried calling that function from the OnStateExit(), doesn't move the object either. Is there something I'm missing about state machine behaviours? Help would be much appreciated!
Answer by rzaba · Sep 07, 2019 at 09:33 AM
I encountered a similar problem recently. I admit that it made me feel confused, but apparently - according to Unity developers - this is the expected behavior. Here's an explanation of what's going on:
When the animator is enabled we do build a super set of bindings by iterating over all animation clip in your controller and combining all bindings. This super set define all the animated property for your controller. At the same moment we do take a snapshot of all those properties as the default values. On each frame that the animator is updated all those properties are written by the animator, properties not animated in the current state are written with the default values, the animated one are written with the value from the curve.
As I see it, there are different ways to fix it:
Inside OnStateExit, retrieve a component that controls the GameObject that is meant to teleport. Set a boolean flag inside that component to true. You would then handle the teleporting functionality inside your component's LateUpdate, based on that boolean flag. Something like this:
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { Instantiate(parSys, new Vector3(-0.038f, 0.05f, 0.694f), Quaternion.identity); var teleporter = gameObjectToTeleport.GetComponent<Teleporter>(); teleporter.ShouldTeleport = true; }
Teleporter class:
public class Teleporter : MonoBehaviour
{
public bool ShouldTeleport = false;
void LateUpdate()
{
if (ShouldTeleport)
{
transform.position = new Vector3(Random.Range(-2f, 2f), 0.05f, Random.Range(-2f, 2f));
ShouldTeleport = false;
}
}
}
I don't have the full context of your project, but in my case, simply calling animator.Update(0.0f) was enough to make it work. Example:
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { animator.gameObject.transform.position = new Vector3(5.0f, 0.0f, 0.0f); animator.Update(0.0f); }
P.S. In both cases, you might want to make sure that the "Apply Root Motion" checkbox is checked on your Animator.
Some additional resources that might help you:
Hello, Thank you very much for your help, the first solution did it for me. The second did not work because I needed to move an object that the animator was not attached too (I think that was the problem).
Also, I needed to read the reposted text about the logic behind state machine behaviours a few time to get it, but I think I understand them better now, thank you.
Your answer
Follow this Question
Related Questions
[StateMachineBehaviours] All prefabs share same state machine. 0 Answers
State Machine Behaviour OnStateEnter Check previous state? 1 Answer
Unity OnStateExit StateMachineBehaviour is never getting called 0 Answers
Interface state structure with different type of enemies 0 Answers
Easier way of creating transitions in the animator? 1 Answer