- Home /
Snapping Child to Root after Animation
Hello Unity people,
I am having a tough time trying to get animations to work with 2D characters in Unity 4.3. I have a character made of parented Sprites (it doesn't have a skeleton or any bones) and I want to change his position through animations created in Unity. However, to my knowledge, you can't do root motion with Unity animations. My current solution to this is only moving the child of the root through animation, then saving the child's position, setting the child's localPosition to Vector3.zero, and finally moving the root to the saved child's position. Unfortunately, when I do this, I can see the objects snapping into place and obviously I can't have that.
My code for this was:
void Snap()
{
var savedPosition = Child.position;
Child.localPosition = Vector3.zero;
Root.position = savedPosition; // getting called first
}
After some testing I discovered that the last line was getting called before the one above it, which I thought was weird. So I wrote this:
IEnumerator Snap()
{
var savedPosition = Child.position;
Child.localPosition = Vector3.zero;
yield return new WaitForEndOfFrame();
Root.position = savedPosition;
}
This actually got rid of the flicker that happened with the other method. So, I guess my questions are:
Shouldn't the line above it be called first no matter what? The root was moved first, then the child's local position was reset to zero in both methods.
Why does waiting til the end of frame get rid of the flicker?
Is there a better way to do this?
Sorry for the long winded post. Thanks in advance.
Answer by nkvnkv · Sep 30, 2014 at 09:32 PM
Had a similar problem how ever I am snaping root to child after child animation is done,
solved it by using an empty state (ChangeRoot) in mecanim state machine animation with no animation.
During ChangeRoot i am snaping root to child.
A and B states are Idle animation on start and destination while transfer state is playing animation between A and B.
Child (Animated object) has animator component and root which is just empty object with transform.
Child Script
using System.Collections;
using UnityEngine;
[RequireComponent(typeof(Animator))]
public class RootMotionScript : MonoBehaviour
{
public Vector3 lastPosition;
private int HashA = Animator.StringToHash("Base Layer.A");
private int HashB = Animator.StringToHash("Base Layer.B");
private int HashChangeRoot = Animator.StringToHash("Base Layer.ChangeRoot");
private int HashX = Animator.StringToHash("X");
private int HashY = Animator.StringToHash("Y");
private int HashZ = Animator.StringToHash("Z");
private int BoolDone = Animator.StringToHash("Done");
private int BoolMoveing = Animator.StringToHash("Moving");
private Animator anim;
private AnimatorStateInfo stateCurrent;
private AnimatorStateInfo stateNext;
private void Start()
{
lastPosition = Vector3.zero;
anim = GetComponent<Animator>();
anim.SetBool(BoolDone, false);
anim.SetBool(BoolMoveing, false);
}
private void Update()
{
stateCurrent = anim.GetCurrentAnimatorStateInfo(0);
stateNext = anim.GetNextAnimatorStateInfo(0);
anim.SetFloat(HashX, transform.localPosition.x);
anim.SetFloat(HashY, transform.localPosition.y);
anim.SetFloat(HashZ, transform.localPosition.z);
if (stateCurrent.nameHash == HashChangeRoot)
{
anim.SetBool(BoolMoveing, true);
SnapRoot();
anim.SetBool(BoolMoveing, false);
}
if (stateCurrent.nameHash == HashA)
{
}
if (stateCurrent.nameHash == HashB)
{
AssignLastPosition();
}
}
public void AssignLastPosition()
{
// Debug.Log("assign");
lastPosition = anim.rootPosition;
//adjustment
lastPosition = new Vector3(lastPosition.x, lastPosition.y, lastPosition.z - 20);
anim.SetBool(BoolDone, false);
}
public void SnapRoot()
{
//if (stateNext.nameHash == HashA && WasMoved)
if (anim.GetBool(BoolMoveing) && !anim.GetBool(BoolDone))
{
anim.SetBool(BoolDone, true);
//Debug.Log("snap");
//ShowCurrentPosition("A again", "parent", transform.parent.position);
new WaitForEndOfFrame();
transform.parent.position = lastPosition;
}
}
private void Positions(string point)
{
ShowCurrentPosition(point, "root", anim.rootPosition);
// ShowCurrentPosition(point, "body", anim.bodyPosition);
//ShowCurrentPosition(point, "pivot", anim.pivotPosition);
// ShowCurrentPosition(point, "delta", anim.deltaPosition);
}
private void ShowCurrentPosition(string state, string type, Vector3 pos)
{
Debug.Log(state + " position " + type + ": " + pos);
}
}
I find this to be the best way to rooted animation move using mecanim which must use root motion.
Answer by Spinnernicholas · Sep 30, 2014 at 09:33 PM
For root animations, put everything in a root object and then animate through the root.
Root{
Torso{
Head
Arm{
Arm{
Hand
}
}
Arm{
Arm{
Hand
}
}
Leg{
Leg{
Foot
}
}
Leg{
Leg{
Foot
}
}
..........
}
}
Your answer
Follow this Question
Related Questions
2D Animation does not start 1 Answer
Animation Lag when Changing Movement Direction 2D (4.3) 2 Answers
Sprite becomes invisible when set on animator 0 Answers
Scriptable root motion? 1 Answer
2D animation diferent right and left 0 Answers