June 13, 2012 2 Comments
I was searching through the sparse official documentation on NavMesh and NavMeshAgent and found very little functional explainations and implementation. So I decided to just play with it… whats the worst that could happen, right?
Note: This requires Unity3D Pro – NavMesh baking is only supported in Pro. Also, I have not played much with the A* extension Aron Granberg put together. It looks great however for true A* and I intend to play with it.
Most examples and tutorials and posts out there all utilize NavMesh for controlling AI characters. And they typically are all “make AI follow this sphere you can move around”. Kudos to all those efforts, as they are still very useful. However, I was looking for a different solution. I wanted pathfinding very quickly for my character and not AI, backed with a Click To Move style controller.
Step 1. Unity3D Pro. Check.
Step 2. Plane or smashed cube to “walk on”. Throw in more simple geometry for walls and “steps”. I quote walk on and steps because they are configurable to a great degree. Layer masking for walkable surface types and like most character controllers, the steps have max height values (navmeshagents also have jump heights too which is neat).
Step 3. Window->Navigation. Check the Show NavMesh button in the window that overlayers the scene (if you dont see this make sure the Navigation tab is selected near the Inspector window… showing that window defaults it to tab next to Inspector).
Step 4. On Navigation tab, click bake. You’ll see all of the blue shading that shows the navmesh an agent can traverse.
So that is simple enough. The scene now includes all the pathing information. Now to let my player use the navmesh, I have to make it an agent. I’d stress this point: while learning this, do not make the assumption that NavMeshAgent’s are AI. They don’t have to be. Is that its intended use? Maybe. Probably. Doesn’t mean its only use is controlling AI. I am not going to delve into click to move style 3rd person controlling. I will assume you have a rig already, or just using basic geometry with a nested camera to track movement.
Step 5. Add NavMeshAgent component to whatever gameobject that you want to adjust the transform for. This is an important note… A basic approach in scene graphs is nesting objects to inherit transforms. Whereever the agent is, becomes the “root” that moves.
Step 6. In the click to move method, you essentially cast a ray from mouseclick to intersect with geometry / terrain that is generally on specific layers. Having that destination vector allows the agent to kick off. NavMeshAgent::SetDestination(Vector3). To the right is a very crude detection and implementation.
A feature I wanted was to stop the player on a current path either by choice (forcing an action in place) or not by choice(player gets rooted by an enemy). So some more exploratory programming was needed. Fortunately, NavMeshAgent::Stop exists. It has an override to disable updates. This is critical. I was getting rotation snapping results when I was trying to orient a “rooted” player towards the current mouse click. Without stopping the agent transform updates, when you set a new destination or resume the path, the controlled object will snap back to its “nav mesh” tranform and not begin where the lookAt vector3 rotation was last (because its not applied through the nav mesh component, but to the object itself).
Note: If anyone knows a way to bypass this completely and control it via the NavMeshAgent component – I’m all ears… I’d prefer that. It was late however, and I didn’t want to spend more time on this before moving on.