Applying Root Motion to your character is a very practical and accurate way of animating it. However, every now and then you might need to manually control one or more aspects of the character's movement. Perhaps you only have an in-place animation to work with, or maybe you want the character's movement to be affected by other variables. In such cases, you will need to override Root Motion via script.
In this recipe, we will control the character's movement via script, making it rotate and jump.
For this recipe, we have prepared a project named MixamoProject
, containing several assets such as levels, animated characters, and props. You can find it inside the 0423_05_codes
folder.
To apply Root Motion via script, perform the following steps:
05_04
(inside the Levels
folder). Note that it includes a S.W.A.T. character, featuring the Animator component using the swatController03 Controller.Swat@turning_right_45_degrees
file.Jump
, TurnLeft
, and TurnRight
. Then, in the gridded area, create the states Jump, TurnLeft, and TurnRight.public float transitionTime = 0.25f;
, add the following code:public float jumpSpeed = 4.0F; public float gravity = 20.0F; private float jumpPos = 0.0f; private float verticalSpeed = 0; private float xVelocity = 0.0f; private float zVelocity = 0.0f;
if(controller.isGrounded){
, add the following code:if (Input.GetKey(KeyCode.Space)) { animator.SetBool("Jump", true); verticalSpeed = jumpSpeed; }else{ animator.SetBool("Jump", false); } if(Input.GetKey(KeyCode.Q)){ animator.SetBool("TurnLeft", true); transform.Rotate(Vector3.up * (Time.deltaTime * -45.0f), Space.World); } else { animator.SetBool("TurnLeft", false); } if(Input.GetKey(KeyCode.E)){ animator.SetBool("TurnRight", true); transform.Rotate(Vector3.up * (Time.deltaTime * 45.0f), Space.World); } else { animator.SetBool("TurnRight", false); }
void OnAnimatorMove(){ Vector3 deltaPosition = animator.deltaPosition; if(controller.isGrounded){ xVelocity = animator.GetFloat("Speed") * controller.velocity.x * 0.25f; zVelocity = animator.GetFloat("Speed") * controller.velocity.z * 0.25f; } verticalSpeed += Physics.gravity.y * Time.deltaTime; if(verticalSpeed <= 0){ animator.SetBool("Jump", false); } deltaPosition.y = verticalSpeed * Time.deltaTime; if(!controller.isGrounded){ deltaPosition.x = xVelocity * Time.deltaTime; deltaPosition.z = zVelocity * Time.deltaTime; } controller.Move(deltaPosition); if ((controller.collisionFlags & CollisionFlags.Below) != 0){ verticalSpeed = 0; } transform.rotation = animator.rootRotation; }
We took two different paths to modify our character's transform settings. First, we used the Rotate
command, as in transform.Rotate(Vector3.up * (Time.deltaTime * -45.0f), Space.World)
, to make the character actually turn around when the Q and E keys are held down. This command was used in conjunction with animator.SetBool("TurnLeft", true)
, which triggered the correct animation clip.
Also, we used Unity's OnAnimatorMove()
function for overriding the animation's original Root Motion. Observe that, once this function is added to the script, the field Apply Root Motion on the Animator component changes from a checked box to Handled by Script. In our case, we used it to learn about the character's speed and direction while he is grounded, in order to apply it once he jumps. We also apply gravity when calculating his position, in case his feet are not touching any surface.
18.219.4.174