Search Unity

Reparenting and resetting child's transform properties offsets it from parent (using Timeline animat

Discussion in 'Timeline' started by lifGwaethrakindo, May 13, 2022.

  1. lifGwaethrakindo

    lifGwaethrakindo

    Joined:
    Oct 22, 2017
    Posts:
    3
    I am beginning to use Unity's Timeline for the first time.

    I am creating a simple intro sequence where the Animator Gameobject does a position displacement animation (the movements and rotations are too complex to make some sort of waypoint system, making an Animation was the best way to go). And then, after the sequence is done, I reposition the parent so its Animator child has a local position of { 0, 0, 0 }.

    The problems is that when I do that, the child offsets itself and I realized it has to do with the animation and the root motion, which the Timeline activates on its own but ignores if I set it to false.

    The hierarchy of the objects is as simple as this:

    • Parent
      • Child Animator
    The main code that does all the aforementioned is the following:


    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Playables;
    6.  
    7. [RequireComponent(typeof(PlayableDirector))]
    8. public class TEST_MoskarIntroAnimation : MonoBehaviour
    9. {
    10.     [SerializeField] private Transform parent;
    11.     [SerializeField] private Animator animator;
    12.     private PlayableDirector director;
    13.  
    14.     /// <summary>TEST_MoskarIntroAnimation's instance initialization.</summary>
    15.     private void Awake()
    16.     {
    17.         director = GetComponent<PlayableDirector>();
    18.     }
    19.  
    20.     /// <summary>TEST_MoskarIntroAnimation's starting actions before 1st Update frame.</summary>
    21.     private IEnumerator Start ()
    22.     {
    23.         director.Play();
    24.        
    25.         float duration = (float)director.duration;
    26.         WaitForSeconds wait = new WaitForSeconds(duration);
    27.  
    28.         yield return wait;
    29.  
    30.         Debug.Log("[TEST_MoskarIntroAnimation] Sequence is finished...");
    31.  
    32.         animator.transform.SetParent(null);
    33.         parent.position = animator.transform.position;
    34.         animator.transform.SetParent(parent);
    35.         animator.transform.localPosition = Vector3.zero;
    36.         animator.transform.localRotation = Quaternion.identity;
    37.     }
    38. }
    I have tried:

    Which is reflected on the following class (which is not reflected on the previous sample code but I used for testing, enabling/disabling flags before and after the sequence):

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. [Flags]
    7. public enum Override
    8. {
    9.     None = 0,
    10.     DontOffsetFromParent = 1,
    11.     ApplyRootMotion = 2,
    12.     ApplyBuiltinRootMotion = 4
    13. }
    14.  
    15. [RequireComponent(typeof(Animator))]
    16. public class OnAnimatorMoveOverrider : MonoBehaviour
    17. {
    18.     [SerializeField] private Override _overrideActions;     /// <summary>Things to override on OnAnimatorMove.</summary>
    19.     private Animator _animator;                             /// <summary>Animator's Component.</summary>
    20.  
    21.     /// <summary>Gets and Sets overrideActions property.</summary>
    22.     public Override overrideActions
    23.     {
    24.         get { return _overrideActions; }
    25.         set { _overrideActions = value; }
    26.     }
    27.  
    28.     /// <summary>Gets animator Component.</summary>
    29.     public Animator animator
    30.     {
    31.         get
    32.         {
    33.             if(_animator == null) _animator = GetComponent<Animator>();
    34.             return _animator;
    35.         }
    36.     }
    37.  
    38.     /// <summary>Callback for processing animation movements for modifying root motion.</summary>
    39.     private void OnAnimatorMove()
    40.     {
    41.         if((overrideActions | Override.DontOffsetFromParent) == overrideActions)
    42.         {
    43.             Transform parent = transform.parent;
    44.  
    45.             if(parent == null) return;
    46.  
    47.             Vector3 position = parent.position;
    48.             position = animator.deltaPosition;
    49.             parent.position = position;
    50.         }
    51.         if((overrideActions | Override.ApplyBuiltinRootMotion) == overrideActions) animator.ApplyBuiltinRootMotion();
    52.  
    53.         animator.applyRootMotion = ((overrideActions | Override.ApplyRootMotion) == overrideActions);
    54.     }
    55. }
    But either it does nothing or does not let the Timeline to do the animation. I don't want to patch a solution where I animate a copy and after the sequence I deactivate that copy and put the one that plays on the scene, since it is something that would be implemented to many more characters and they have many dependencies on other components, and I don't feel that it would be wise to make Animator-only copies given the fact that the originals may change, and so on.

    Any more information I may need to provide, please let me know, and thanks in advance.