In this recipe, we will use animations to move and steer our character.
Getting ready
To use root motion for steering, you need to prepare a character with at least four animations: Idle, WalkForward, WalkLeft, and WalkRight. WalkRight and WalkLeft should make the character walk in circles (clockwise and counterclockwise). You don't need to create a full circle, just make sure that the start and end poses of the animation look similar. As always, all the animations should have contact points of the feet in the same normalized time. Make sure not to switch the left and right foot. If you start
the WalkForward animation with the left foot forward, both WalkLeft and WalkRight animations should also start with the left foot forward, as shown in the following screenshot:
Steering animations using root motion
You can also use the example project; go to the Chapter 04 Character
movement\Recipe 03 Using root motion to steer a character directory. You can find the Example.unity scene there, with a Humanoid character already animated in the scene's Hierarchy. You can start the game and use the WSAD keys to move the character relative to the camera. In the Rigs directory, you can find the Humanoid.fbx character with all the required animations.
How to do it…
To use root motion for steering, follow these steps:
Import your character with Idle, WalkForward, WalkLeft, and WalkRight root 1. motion animations into Unity.
Select the character asset file and go to the Inspector. Make sure the Animation 2. Type is set properly for your character (Generic or Humanoid). If you are using
a Generic character, make sure to set its Root Node.
Go to the Animation tab and select the Idle animation. Select all the Bake Into 3. Pose options and set the Base Upon option of the Root Transform Rotation
to Original.
For the WalkForward animation, select the same options as for the Idle 4. animation, but uncheck Bake Into Pose for Root Transform Position (XZ).
For the WalkLeft and WalkRight animations, set all the option the same as for 5. the WalkForward animation, but additionally uncheck the Bake Into Pose option
for Root Transform Rotation.
Set the Loop Time options to true for these animations.
6.
If your animations don't loop perfectly, you can try out the Loop Pose option. It 7. will force the start and end poses to loop.
Apply the import settings.
8.
Place your character into a scene.
9.
Select it in the Hierarchy and add a Capsule Collider to it. You may need to 10. adjust the Capsule Collider properties to better fit your character. In our
examples, we need to set the Height property to 2 units and the Y axis in the Center property to 1 unit.
Add a Rigidbody component to the character and set its Constraints to Freeze 11. Rotation in every axis.
Navigate to the Animator component of the character (it is added automatically 12. for animated game objects). Set Update Mode to Animate Physics. Make sure
the Apply Root Motion option is checked in the Animator component.
Create an Animator Controller asset for the character.
13.
Drag and drop the Idle animation into the Animator Controller to make it the 14. default state.
Create float Speed and float Direction parameters in the Animator 15. Controller.
Right-click on the empty space in the Animator Controller and choose Create 16. State | New From Blend Tree.
Click on the Blend Tree and change its name in the Inspector to Steering.
17.
Double-click on the Blend Tree to open its settings.
18.
Click on the plus button and choose the Add Motion Field option three times.
19.
Set the Parameter of the Blend Tree to Direction; we will only use the Direction 20. parameter for blending walk animations.
Drag and drop the WalkLeft animation in the first (upper) field,
21. the WalkForward in the second (middle) field, and WalkRight in the third (lower) field.
Uncheck the Automate Thresholds option.
22.
Set the WalkLeft animation Threshold to -45, WalkForward
23. animation Threshold to 0, and the WalkRight animation Threshold to 45.
Double-click on the empty space in the Animator Controller to get out of 24. the Blend Tree settings.
Create two transitions:
25. Idle | Steering with the condition set to Speed parameter greater than 0.5, Has Exit Time set to false, and Transition Duration set to 0.2 seconds.
Steering | Idle with the condition set to Speed parameter less than 0.5, Has Exit Time set to false, and Transition Duration set to 0.2 seconds.
Write a script to set the Speed and Direction parameters of our Animator 26. Controller and assign that script to the character.
You can find the script in the provided Unity project in the Scripts directory of 27. this recipe. It is called RootMotionSteering.cs.
In this script, we make the character move relative to the camera. In
28. the Update() function, first we get and store player input in two variables, hor (for Horizontal input) and ver (for Vertical input):
hor = Input.GetAxis("Horizontal");
ver = Input.GetAxis("Vertical");
As we want to move the character relative to the camera, we're using the camera's 29. forward and right axis to build a desired movement vector. Our camera is not
completely horizontal (it can face slightly down, for instance), so first we need to calculate cameraHorizontalForward by taking the normal camera forward vector, setting its Y axis to 0, and normalizing the vector (so it has a length of 1):
cameraHorizontalForward = new Vector3(cameraTransform.forward.x,
0f, cameraTransform.forward.z).normalized;
In this script, cameraTransform is a public Transform variable to which we 30. attach our in-game camera.
Next we calculate the desiredMoveDirection: this is a vector pointing in the 31. direction that we would like to move our character. This vector points directly to
the right axis of the camera when the player holds the right arrow, to the left of the camera when player holds the left arrow, to the horizontal version of camera's forward axis (cameraForwardHorizontal) when the player holds the up arrow, and to the opposite direction of that vector when player holds the down arrow:
desiredMoveDirection = ver * cameraHorizontalForward + hor * cameraTransform.right;
Next we calculate the angle between our character's forward vector and
32. our desiredMoveDirection vector. We will use this value to set the Direction parameter in the Animator Controller. The Vector3.Angle() method returns an angle between two vectors. This angle is always positive (greater than 0).
Therefore, we use the dot product of the desiredMoveDirection
and transform.right (our character's right axis) vectors to determine whether the desiredMoveDirection points to the right or to the left of the character (the dot product is greater than 0 for vectors pointing in the same direction and less than 0 for vectors pointing in the opposite direction). We use the Mathf.Sign() method to make sure our dot product value equals -1 or 1. The result is an angle from -180 to 180 degrees; we store the value in the float direction variable:
direction = Vector3.Angle(transform.forward, desiredMoveDirection) *
Mathf.Sign(Vector3.Dot(desiredMoveDirection, transform.right));
Then we calculate a float speed variable's value; it is simply the magnitude of 33. our desiredMoveVector. The speed variable is used to set the Speed parameter
in our Animator Controller:
speed = desiredMoveDirection.magnitude;
Lastly, we use the calculated direction and speed values and set them in our 34. Animator Controller, with a dampTime parameter of the SetFloat() method set
to 0.2 seconds to smooth out the blends. The anim variable stores the reference to the Animator component of our character and is set in the Start() function:
anim.SetFloat("Direction", direction, 0.2f, Time.deltaTime);
anim.SetFloat("Speed", speed, 0.2f, Time.deltaTime);
How it works…
Root motion steering works the same way as the root motion movement. We are using the rotation of the root bone to rotate the character. In our example, the character is walking in circles, so its hips are rotating during the animation. That data is then used to rotate the whole character.
Again, to make the walk animations blend properly, you have to make sure that they all start with the same leg and that the feet contact poses are in the same normalized time as the animation.
If you are using a Humanoid rig, it is enough to create only forward and left animations. Then you can create a new animation clip in the
character Import Settings in the Animation tab (you need to click on the plus button in the Clips section). When you choose the WalkLeft
animation as the source, set it to Mirror and set its Cycle Offset to 0.5; you should get a proper WalkRight animation.