- Home /
 
Correct way to handle root motion with parent game object
So I have a parent game object which is just a container and has all the components included, such as Animator and RigidBody etc. Now one of its children is a humanoid model, lets call them PlayerContainer and the child PlayerModel.
The problem I have is that the root motion seems to be applying to the PlayerModel not the PlayerContainer, now I know there is the OnAnimatorMove event, but I am not entirely sure if I even need this callback on the parent as it seems a bit of a hack to have to keep resetting the parent position to that of the child then resetting the child position each time.
So I assume this is a common thing where animators are on parent objects with the mesh models as children, so is there a special way to get root motion acting as expected here where it moves the root object opposed to the model?
Answer by AngryAnt · Oct 16, 2015 at 09:47 AM
OnAnimatorMove is your friend. Implement it on a component attached to the same GO as the Animator and then forward the call to your movement component on you root GO, where you can apply movement via yourAnimator.deltaPosition.
To clarify for new questions here:
On your child object with the animator, implement a script (you could call it AnimatorForward) with OnAnimatorMove which calls OnAnimatorMove on a target parent script.
In the OnAnimatorMove on that target script on your parent, apply Animator.deltaPosition to your current position - literally transform.position += myAnimator.deltaPosition;
Profit!
I hope that clears any lingering doubt.
Just wanted to update this after our chat to mention that there does seem to be something odd at work with the root motion. If it helps anyone else the animations in question were from $$anonymous$$ixamo and just keep repeating in place, so although AngryAnt solution should work, it won't in this case but no one else seems to have a solution, and a relevant post on mixamo related to this can be found here.
How would that work exactly?
This is what I'm doing on my Animator GO:
     public void OnAnimator$$anonymous$$ove() {
         if (anim) {
             transform.parent.position = anim.rootPosition;
             transform.parent.rotation = anim.rootRotation;
         }
     }
 
                  But the position seems to be wrong on the root GO and not sure what you mean by "where you can apply movement via yourAnimator.deltaPosition."
Wouldn't something like this work, too?
 void OnAnimator$$anonymous$$ove(){
     transform.parent.rotation = anim.rootRotation;
     transform.parent.position += anim.deltaPosition;
 }
 
                  Why the need to pass the function to the parent transform?
That would indeed work just fine. But it would only cover the scenario where the transform you wish to move is indeed the immediate parent of the animator.
lmaoooo just do
 transform.parent.parent.parent.parent.parent
                   Answer by AubreyH · Jul 03, 2018 at 06:58 PM
Hello. I have a vaguely related problem that I thought I might talk about here in case someone encounters it.
When you use root motion with your own playables system, and you have animations that loop, you will see that your final skeleton will jump back.
I believe that the Animator is secretly aware of WHEN an animation loops, and at this point it increments skips passing on the "back to the beginning" delta, so that you get an uninterrupted accumulation on rootPosition and rootRotation.
But, if you are making your own playable, the system isn't implicitly aware of this going on, so you must cope with it manually.
In my case, I have the normalized time of my entire blend tree system, and can monitor the moment that it goes from >0.5f to <0.5f. On this frame, I just re-use the previous frame's delta, instead of the given delta (which would jump my character back to where they began).
I hope this helps someone.
Answer by theANMATOR2b · Jul 07, 2016 at 09:33 PM
Seems like the container is the problem here.
Removing the container and applying the components to the character directly will allow root motion to work correctly.
Or am I missing something from the above information? 
Unless the mixamo animations do not have root motion to begin with.
In theory @AngryAnt solution should work without any need to stop having a parent GameObject. I just want to know what is the correct code to write in order for it to work.
$$anonymous$$e being a noncoding artist I usually search for the simplest solution to solve problems without code, and then look for work arounds to issues resulting from deviating from the simplest solution when additional elements are added to the mix.
Since code is nearly sanskrit to me I will graciously continue to follow without interrupting. Hope you find the solution. 
In my case, Container is necessary for displaying random models (which has animator on them) in a single "enemy" entity.
So every time I create an enemy object, it creates a random model as a child and that child's animator must move the parent enemy object; Not the child.
Answer by Desertleaf · Dec 30, 2020 at 01:32 AM
All the Solutions mentioned above will always be "Catch up and Reset" whenever you have a child object moving.
To avoid this cat and mouse chase and reset, the child object must NEVER move. Instead, turn off the root motion on the child , Copy its animator component, and paste it into the Parent Object. With this, you will notice the parent object now moves correctly according to the applied Root motion data; however, the child object contains its own animator and it will remain uninfluenced.
You will need to create a script to Sync both animator triggers. The Parent animator will allow your NavMesh Agent to move correctly, but the challenge is to make sure your Child Object animator is playing on the same speed and frame of the Parent Animation.
Summary: Avoid Cat and Mouse, and change it up to a challenge of Animation Synchronization. One must be aware that this now leads to a funky problem on slow, failing, and struggling machines. Your Parent will always trigger before your child. If the computer fails or slows down on the frame between the triggering of your Child and Parent, the appearance and travel will produce different results until both are told to stop. In different words, The child object is now a visual, and your parent is now the root motion object.
I'm afraid this is a misunderstanding of how OnAnimatorMove works still today - six years after the question was asked and answered. You can think of it like this:
When root motion has been calculated, the animator will populate its exposed delta values and send an
OnAnimatorMovemessage to theGameObjectto which it is attached.If no custom implementation is found then effectively a default implementation is invoked, which just applies those deltas to the
Transformof thatGameObject.If in stead a custom implementation is found, then that implementation is invoked and that is the end of it - leaving it up to you how and where the delta is applied: Fed to a parent object like here / applied to a rigidbody / navmeshagent / network mover interface / whatever.
What you are proposing is way more error prone, full of admitted side effect and entirely unnecessary.
Answer by QuarterMillion · Jul 27, 2021 at 07:01 AM
I've been grappling with a desire to try to remotely move multiple Avatars by remotely referencing their Rigidbodies/AnimatorControllers. But on a recent error it was pointed out to me that the OnAnimatorMove function only inherits from this as in this.gameObject(the one its expected to be directly attached to).
And while its entirely possible to remotely reference and allow multiple gameObject transforms to be controlled through a single script with a for loop( like say for multiplayer game?) I haven't as much success with doing the same with rigidbodies.
My understanding of Rigidbodies however is that they are each directly attached to their own respective CapsuleCollider. As such since each Capsule Collider also has its own Collison functions, this suggests that you must have a script attached to each gameObject for those components which possibly extends to the animator controller. I could imagine (and had coded an alternative way) that uses arrays to grab/store/reference multiple AvatarGameObjects, Rigidbodies, and AnimatorControllers but Unity apparently based on the reasons mentioned above does not support this.
All that is to say OnAnimatorMove is a singular object function hence a networked(cleaner code) implementation isn't really supported at all.
Which in retrospect makes sense. If it was an online game who exactly would control what avatar. Locally however this should be fine and allowed. Think about all those multiplayer arcade games or multiplayer home console games.
Your answer
 
             Follow this Question
Related Questions
How do I move a model with its walk animation? 2 Answers
Mecanim curve for move speed 0 Answers
Mecanim: 2D Blend Trees, Unable to Compute Positions. 0 Answers
Mecanim - how can I use traslation and rotation of Root from separate animation clips? 0 Answers
Does anybody have best practices on creating an action-adventurer character (Mecanim)? 0 Answers