Object change position up when setting animator component enable true

I have a model not my own one that with a script I loop over the root main model and all it’s children and turn on/off all the Animators. The game start when all the animators are disabled so the model is turned off.

This script is attached to the model :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AnimFlyertransportationController : MonoBehaviour
{
    public GameObject JetFlame;
    public bool turnOffOn = false;

    // Start is called before the first frame update
    void Start()
    {
        TurnAllAnimtorsOff(transform, turnOffOn);

        if (turnOffOn)
        {
            JetFlame.SetActive(true);
        }
        else
        {
            JetFlame.SetActive(false);
        }
    }

private void TurnAllAnimtorsOff(Transform root, bool onOff)
    {
        Animator[] animators = root.GetComponentsInChildren<Animator>(true);

        foreach (Animator a in animators)
        {
            if (onOff)
            {
                a.enabled = true;
            }
            else
            {
                a.enabled = false;
            }
        }
    }

    private void OnValidate()
    {
        TurnAllAnimtorsOff(transform, turnOffOn);

        if (JetFlame) JetFlame.SetActive(turnOffOn);
    }
}

When the game start the model is on the ground :

Then I enable true the flag and it’s changing all the animator to enable true but then the model object is changing position and move up :

This is the animator controller settings of the animation that make the spacecraft to be idle in the inspector :

I also tried to change the root motion of all the animators to be false :

if (onOff)
            {
                a.applyRootMotion = false;
                a.enabled = true;
            }

but nothing helped so far. Thr object move up jump up at once when setting the animators true.

I mean your Jet Frame is On right, aren’t you supposed to be up in the air?
if you turn off which animation take your Flyer back down then. if there no landing going on then your Flyer is going keep up and up

1 Like

turn Animator off isn’t mean you return back to where you started, your Flyer just stay to where it is

1 Like

I understand what your mean.

I tried something and got a bit messed with the bool flags.
I did that the default state machine when the game start will be takeoff but the animators also will be disabled :

The spacecraft is on the ground when the game start :

Now when the game is running and I set the flag Turn On Off to be true it will start the spacecraft and also will move it up smooth as taking off :

Now when I set the Land flag to true I want it to play the landing animation and also turn off all the animators and the engine. It’s landing but not turning off the animators and engine and if I’m doing :

f(land == true && turnOffOn)
        {
            animators[0].Play("Anim_Flyer_Land");

            TurnAllAnimtorsOff(transform, false);
            JetFlame.SetActive(false);
            turnOffOn = false;


            land = false;
        }

Then it’s turning everything off but the spacecraft never land.

I want that with one bool it will turn on and take off and with the second bool it will land first then turn everything off and so on. maybe even to do it with one bool. but now I messed all the flags.

all you need to do is to check when “Anim_Flyer_Land” is finished, for right now you are force to enables animator before land animation even finish it.

write a logic that wait for landing animation to finished first then turn it all of.

1 Like

I tried this the checking script if the animation still playing :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckAnimationEnd : MonoBehaviour
{
   public GameObject _animator;
   public string animStateName;

   private Animator _ani;

   // Start is called before the first frame update
   void Start()
   {
       _ani = _animator.GetComponent<Animator>();
   }

   // Update is called once per frame
   void Update()
   {
       if (animStateName != null && animStateName != "" && _ani != null)
           IsPlayingAnimation();
   }

   public bool IsPlayingAnimation()
   {
       bool IsOffLand = false;

       if (_ani != null)
       {
           if (!_ani.GetCurrentAnimatorStateInfo(0).IsName(animStateName))
           {
               IsOffLand = true;
           }
           else
           {
               IsOffLand = false;
           }
       }

       return IsOffLand;
   }
}

And then :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AnimFlyertransportationController : MonoBehaviour
{
   public GameObject JetFlame;
   public CheckAnimationEnd checkAnimEnd;
   public bool turnOffOn = false;

   private Animator[] animators;

   // Start is called before the first frame update
   void Start()
   {
       TurnAllAnimtorsOff(transform, turnOffOn);

       if (turnOffOn)
       {
           JetFlame.SetActive(true);
       }
       else
       {
           JetFlame.SetActive(false);
       }
   }

private void TurnAllAnimtorsOff(Transform root, bool onOff)
   {
       animators = root.GetComponentsInChildren<Animator>(true);

       foreach (Animator a in animators)
       {
           if (onOff)
           {
               a.enabled = true;
           }
           else
           {
               a.enabled = false;
           }
       }
   }

   private void OnValidate()
   {
       TurnAllAnimtorsOff(transform, turnOffOn);

       if (JetFlame) JetFlame.SetActive(turnOffOn);

       Land();
       TakeOff();
   }

   private void Land()
   {
       if (turnOffOn == false)
       {
           checkAnimEnd.animStateName = "Anim_Flyer_Takeoff";

           animators[0].Play("Anim_Flyer_Land");

           if (checkAnimEnd.IsPlayingAnimation())
           {
               TurnAllAnimtorsOff(transform, false);
               JetFlame.SetActive(false);
               turnOffOn = false;
           }
       }
   }

   private void TakeOff()
   {
       if(turnOffOn)
       {
           checkAnimEnd.animStateName = "Anim_Flyer_Land";

           animators[0].Play("Anim_Flyer_Takeoff");

           if (checkAnimEnd.IsPlayingAnimation())
           {
               TurnAllAnimtorsOff(transform, true);
               JetFlame.SetActive(true);
               turnOffOn = true;
           }
       }
   }
}

but everything is messed now. when I set the TurnOffOn to be true the spacecraft start from up and land and then when set it false it’s taking off and everything turn on/off the animators and fire I messed all the flags and both scripts.

I wrote a coroutine version it wont work on OnValidate(), so I move it to Update()

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimFlyertransportationController : MonoBehaviour
{
    public GameObject JetFlame;
    public bool switchFlyerState = false;

    private Animator[] animators;
    private Animator FlyerAnim;

    [SerializeField]
    private FlyerAnimationStateMode flyerAnimationStateMode = FlyerAnimationStateMode.Ground;

    public enum FlyerAnimationStateMode
    {
        Fly, Ground
    }

    // Start is called before the first frame update
    void Start()
    {
        if (FlyerAnim == null)
        {
            FlyerAnim = GetComponent<Animator>();

            if(flyerAnimationStateMode == FlyerAnimationStateMode.Ground)
            {
                TurnAllAnimtorsOff(transform, false);
                JetFlame.SetActive(false);
            }
        }

        if (switchFlyerState)
        {
            ProcessAnimationState();
        }
    }

    private void TurnAllAnimtorsOff(Transform root, bool onOff)
    {
        animators = root.GetComponentsInChildren<Animator>(true);

        foreach (Animator a in animators)
        {
            if (onOff)
            {
                a.enabled = true;
            }
            else
            {
                a.enabled = false;
            }
        }
    }

    private void OnValidate()
    {
        //if (FlyerAnim == null)
        //{
        //    FlyerAnim = GetComponent<Animator>();
        //    if (flyerAnimationStateMode == FlyerAnimationStateMode.Ground)
        //    {
        //        TurnAllAnimtorsOff(transform, false);
        //        JetFlame.SetActive(false);
        //    }
        //}

        //if (switchFlyerState)
        //{
        //    ProcessAnimationState();
        //}
    }

    private void Update()
    {
        //switchFlyerState will true till the animation done
        if (switchFlyerState)
        {
            ProcessAnimationState();
        }
    }

    private void ProcessAnimationState()
    {
        switch (flyerAnimationStateMode)
        {
            case FlyerAnimationStateMode.Ground:
                {
                    StartCoroutine(WaitForTakeOff(FlyerAnim, "Anim_Flyer_Takeoff", true, FlyerAnimationStateMode.Fly));
                }
                break;
            case FlyerAnimationStateMode.Fly:
                {
                    StartCoroutine(WaitForLanding(FlyerAnim, "Anim_Flyer_Land", false, FlyerAnimationStateMode.Ground));
                }
                break;
        }
    }

    public IEnumerator WaitForLanding(Animator targetAnim, string stateName, bool state, FlyerAnimationStateMode mode)
    {
        targetAnim.Play(stateName);

        //Wait until we enter the current state
        while (!targetAnim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
        {
            yield return null;
        }

        //Now, Wait until the current state is done playing
        while ((targetAnim.GetCurrentAnimatorStateInfo(0).normalizedTime) % 1 < 0.99f)
        {
            yield return null;
        }

        //Done playing. Do something below!
        TurnAllAnimtorsOff(transform, state);
        JetFlame.SetActive(state);
        flyerAnimationStateMode = mode;
        switchFlyerState = false;
    }

    public IEnumerator WaitForTakeOff(Animator targetAnim, string stateName, bool state, FlyerAnimationStateMode mode)
    {
        TurnAllAnimtorsOff(transform, state);
        JetFlame.SetActive(state);

        targetAnim.Play(stateName);

        //Wait until we enter the current state
        while (!targetAnim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
        {
            yield return null;
        }

        //Now, Wait until the current state is done playing
        while ((targetAnim.GetCurrentAnimatorStateInfo(0).normalizedTime) % 1 < 0.99f)
        {
            yield return null;
        }

        //Done playing. Do something below!
        flyerAnimationStateMode = mode;
        switchFlyerState = false;
    }
}

https://www.youtube.com/watch?v=5L9ksCs6MbE

1 Like

This is working great. The other problem I see now is when the game start the object is on the ground but when setting the TurnOffOn to true the spacecraft move up then when set to false it’s moving down but not to the ground as before it stay a bit above the ground.

Now sure if it’s easy if at all to solve because it looks like when it’s taking off it’s first changing position a bit up then take off and then when landing the animation stop when the spacecraft is a bit above the ground.

but that’s maybe another question/problem ?

I created here a very short video clip that show the height problem when taking off and when landing :

https://www.youtube.com/watch?v=u0FtT7YYzv4

Your flyer has a parent, make sure your flyer local space Y position is on the correct position. if it still didn’t fix then check the animation clip origin.

if it was animation clip origin then You can fix by editing the first animation’s key in TakeOff Animation Clip and the last key in Landind Animation Clip.

that are one of the many con of using root animation
root animation you will end up writing a lot of code just to make it feel right and the code can get very easy messy and you already see it by yourself.

I’m not biased against root animation, but for me it is easier and lesser problems to just procedural animate with code for a simple transition, because it’s real time dynamic.