• No results found

Using root motion to drive a NavMesh Agents' movement with animations

In document Unity 5.x Animation Cookbook (Page 148-152)

In this recipe, we will use root motion to move and steer a character with a Nav Mesh Agent component. This can be used to get rid of foot sliding in this type of character.

Getting ready

We are going to use the same character as in the previous recipe with all its animations. You should have a character with at least the Idle, WalkLeft, WalkForward, and WalkRight animations ready and set up in the Animator Controller the same way as in the Using root motion to steer a character recipe. You can also go to the Chapter 04 Character

movement\Recipe 07 Using root motion to drive Navmesh Agents movement with animations directory. You will find an Example.unity scene there. Open it, play the game, and click on the ground to make the characters move using NavMesh Agents and root motion.

How to do it…

To use root motion for moving and steering a character with Nav Mesh Agent component, follow these steps:

Import the character with the Idle, WalkLeft, WalkForward, and WalkRight 1. animations and set it up the same way as in the Using root motion to steer a

character recipe, but don't write the RootMotionSteering.cs script as we will create a new one.

Add the Nav Mesh Agent component to the character. Make sure it also has 2. the Capsule Collider component and the Rigidbody component with frozen

rotation in every axis. Also make sure that the Animator component's Apply Root Motion option is set to true and Update Mode set to Animate Physics (the same way as in the Using root motion to steer a character recipe).

Bake the NavMesh in the scene. To do so, make sure your ground model has a 3. collider attached (you can use the Mesh Collider component). Then go

to Window | Navigation. Select the ground in your scene and set it to Navigation Static in the Object tab of the Navigation window. Click on the Bake button at the bottom of the Navigation window. After a short while, NavMesh should be baked (it is visible in the scene as a light blue,

semitransparent mesh covering the ground model). It is needed for our NavMesh Agent to work.

If your character is using any scripts from this book, remove them from 4. its Inspector (we don't need the Jump, RootMotionSteering,

and SetRawDirectionAndSpeed scripts).

Create a new script and call it NavMeshAgentWithRigidBody.cs. We will use 5. both the NavMesh Agent and the Rigidbody components in this script.

In the Update() function of the script, we first disable updating rotation and 6. position in the NavMesh Agent. That will prevent the agent from moving our

character's transform. Then we calculate the float direction variable's value.

We do it in a very similar way to what we did in the Using root motion to steer a character recipe, but instead of creating our own desiredMoveDirection vector, we are using the NavMesh Agent's desiredVelocity vector. This vector describes the speed and direction the agent would like to move with:

agent.updatePosition = false;

agent.updateRotation = false;

direction = Vector3.Angle(transform.forward, agent.desiredVelocity) *

Mathf.Sign(Vector3.Dot(agent.desiredVelocity, transform.right));

In the preceding code agent is the variable in which we store the reference to the Nav Mesh Agent component. We set this reference in the Start() function.

Next we calculate the float speed variable value: it's simply the magnitude of 7. the agent.desiredVelocity vector. We also set

the Direction, Speed, DirectionRaw, and SpeedRaw parameters in our Animator Controller using the anim variable that stores the reference to the Animator component. The anim variable is set in the Start() function. Lastly, we set the agent.nextPosition to be the same as our transform position every frame. This prevents the agent from moving away from our character's transform.

Save the script and attach it to the character.

8.

We also need a script to tell the NavMesh Agent where we want to go. There is 9. a ClickToMove.cs script in the Shared Scripts folder in the provided Unity

example. In the Update() function, we use the agent.SetDestination() method when the player presses the left mouse button. A ray is cast from the mouse cursor position in the main camera's forward direction. If the ray hits a collider, the hit position is used to set the new destination for the NavMesh Agent:

if (Input.GetKeyDown(KeyCode.Mouse0)) {

if (Physics.Raycast(Camera.main.ScreenPointToRay(

Input.mousePosition), out hit)) {

agent.SetDestination(hit.point);

} }

In the preceding code agent is a public NavMeshAgent variable that stores the reference to the Nav Mesh Agent component. We assign this reference manually in the Inspector by dragging the game object with the Nav Mesh Agent component to the Agent field of the script. The hit variable is a global RaycastHit variable that is used by

the Physics.Raycast() method to store the ray cast result.

Save the script and attach it to the character. Drag and drop the character game 10. object to the Agent field of the script (the script is attached to the same game

object but can be attached to any game object).

Play the game and click on the ground to see the character move using 11. both NavMesh Agent and root motion.

How it works…

This recipe has a few key elements that make it work:

NavMesh and NavMesh Agent: Nav Mesh Agent component is used to navigate in the game level with a baked NavMesh. Without one of those elements, our character wouldn't be able to move effectively with point and click input.

Disabling the agent's updateRotation and updatePosition: By default, NavMesh Agents update the rotation and position of a game object. To use root motion, we need to disable this feature and update the game object's position and rotation with the root node animation instead.

Rigid Body and Animator with Apply Root Motion set to true: We use Rigid Body to have collisions between all the objects in the game (not only

other NavMesh Agents) and we use the Apply Root Motion option in the Animator to make the character move with root node animation.

There's more…

In the Scripts directory of this recipe, you can also find a NavAgent.cs script that uses root motion without the Rigidbody component. The Update() function of the script is very similar to the NavMeshAgentWithRigidBody.cs script that we were using in this recipe, but we enable updating the position by the Nav Mesh Agent component. We only disable rotation updating. We add a OnAnimatorMove() function to the script. This method is called every frame after Unity finishes evaluating all the states in the Animator.

In that function, we set the agent.velocity vector to be the same as the velocity of the root node. We also update the transform rotation to be the same as the root node's rotation:

void OnAnimatorMove() {

agent.velocity = anim.deltaPosition / Time.deltaTime;

transform.rotation = anim.rootRotation;

}

Using triggers to grab an edge while

In document Unity 5.x Animation Cookbook (Page 148-152)