---
title: "Adding AI Navigation"
content_type: tutorial
url: "https://learn.unity.com/course/beginner-scripting-old/unit/roll-a-ball/tutorial/adding-ai-navigation?language=en"
language: en
container_type: course
container_title: "Beginner Scripting"
container_url: "https://learn.unity.com/course/beginner-scripting-old.md?language=en"
unit_title: "3D Beginner Game: Roll-a-Ball"
unit_url: "https://learn.unity.com/course/beginner-scripting-old/unit/roll-a-ball?language=en"
standalone_markdown_url: "https://learn.unity.com/tutorial/adding-ai-navigation.md?language=en"
previous_title: "Displaying Score and Text"
previous_url: "https://learn.unity.com/course/beginner-scripting-old/unit/roll-a-ball/tutorial/displaying-score-and-text?language=en"
previous_markdown_url: "https://learn.unity.com/course/beginner-scripting-old/unit/roll-a-ball/tutorial/displaying-score-and-text.md?language=en"
next_title: "Building the Game"
next_url: "https://learn.unity.com/course/beginner-scripting-old/unit/roll-a-ball/tutorial/building-the-game?language=en"
next_markdown_url: "https://learn.unity.com/course/beginner-scripting-old/unit/roll-a-ball/tutorial/building-the-game.md?language=en"
difficulty: beginner
duration_minutes: 40
unity_version:
  - "6.0"
  - "6.3"
supported_unity_versions:
  - name: "2022.3"
    url: "https://learn.unity.com/tutorial/adding-ai-navigation.md?language=en&version=2022.3"
  - name: "6.0"
    url: "https://learn.unity.com/tutorial/adding-ai-navigation.md?language=en&version=6.0"
  - name: "6.3"
    url: "https://learn.unity.com/tutorial/adding-ai-navigation.md?language=en&version=6.3"
last_updated: "2026-08-04T14:21:35.000Z"
---

# Adding AI Navigation

Set up a NavMesh with obstacles and script win and lose conditions to drive enemy AI and gameplay.

In this tutorial, you will:

- Implement a NavMesh for AI-based enemy navigation.
- Add static and dynamic obstacles to challenge the player.
- Code win and lose conditions using Unity scripting.

## Materials

- [8.1 - Install the AI Navigation package - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/0cb059a6-fcb3-48d4-a8c0-116b3ecac7e2/8.1 - Install the AI Navigation package - Transcript.txt>)
- [8.2 - Create an enemy - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/dcb10c01-617b-40da-a6d1-a72143b4a561/8.2 - Create an enemy - Transcript.txt>)
- [8.3 - Bake a NavMesh - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/cadacdb0-8896-42c1-a658-0a548513f4a6/8.3 - Bake a NavMesh - Transcript.txt>)
- [8.4 - Make the enemy chase the player - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/2d97b9de-23da-442e-8bb4-e9a12c448c00/8.4 - Make the enemy chase the player - Transcript.txt>)
- [8.5 - Create static obstacles - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/5d6b405b-b50d-4261-8c10-bbb81ff6682b/8.5 - Create static obstacles - Transcript.txt>)
- [8.6 - Create dynamic obstacles - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/85d7f2ab-32f2-4477-a330-4908ec6398cd/8.6 - Create dynamic obstacles - Transcript.txt>)
- [8.7 - Set the win and lose conditions - Transcript.txt](<https://unity-connect-prd.storage.googleapis.com/20230831/3b37cef2-7da9-4485-9ed4-4818af3d7b58/8.7 - Set the win and lose conditions - Transcript.txt>)

## 1. Overview

In this tutorial, you will:

- Set up a basic Unity 3D environment with player and enemy GameObjects.
- Implement NavMesh for AI-based enemy navigation.
- Add static and dynamic obstacles to challenge the player.
- Code win and lose conditions using Unity scripting.


By the end of this tutorial, your game will look something like this if the player loses:

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/be083860-5aa9-46dc-9d27-21535021f8ad_8_5.7.3-you-lose-condition.mp4)


And your game will look something like this if the player wins:

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/1e5ec7e2-6bb3-4545-93a8-7d9dc9a00e1c_8_5.7.3-you-win-condition.mp4)

## 2. Create an enemy

Follow the video or text instructions below to create an empty enemy GameObject, add a cube for the enemy’s body, and create a material for the enemy:

[Video](https://connect-mediagw.unity.com/h1/20230828/videos/fa36fd09-c969-4793-b175-9cfee7e33448_8.2_-_Create_an_enemy.mp4)

[Download Transcript](https://connect-prd-cdn.unity.com/20230831/dcb10c01-617b-40da-a6d1-a72143b4a561/8.2%20-%20Create%20an%20enemy%20-%20Transcript.txt)

## 1\.  Create an empty Enemy GameObject.

- Create an empty GameObject and rename it to "Enemy".
- Reset the **Transform** component of the **Enemy** GameObject to position it at the origin.


## 2\.  Add a cube for the enemy’s body.

- In the **Hierarchy** window, right-click on the **Enemy** GameObject and select **3D Object** > **Cube,** then rename it to "EnemyBody".
- Set the **Scale** values to **0.5, 1, 0.5** so that it is a taller rectangular shape.
- Set the **Position** of the **EnemyBody** to **0, 0.5, 0** to position it above the **Ground** GameObject.


## 3\.  Create a material for the enemy.

- Right-click inside the **Materials** folder and select **Create** > **Material**, then rename the material to "Enemy".
- Set the material’s **Base Map** color to whatever color you want for your **Enemy** GameoBject.
- Drag and drop the **Enemy** material onto the **EnemyBody** GameObject in the **Scene** view or **Hierarchy** window.

**Note:** For easier editing, you might want to move the **Enemy** GameObject out of the way a bit. Remember to move the **Enemy** parent GameObject and not just the **EnemyBody** child GameObject.

![](https://connect-mediagw.unity.com/h1/20230921/learn/images/fb5fdc7b-276f-4d66-889a-eea326f14df1_2-EnemyBody-Setup.png)

## 3. Bake a NavMesh

Follow the video or text instructions below to bake a NavMesh on the **Ground** GameObject, and configure what to include in the NavMesh surface:

[Video](https://connect-mediagw.unity.com/h1/20230828/videos/a06cb3d8-35b6-4f87-b6f4-67b4534bac1c_8.3_-_Bake_a_NavMesh.mp4)

[Download Transcript](https://connect-prd-cdn.unity.com/20230831/cadacdb0-8896-42c1-a658-0a548513f4a6/8.3%20-%20Bake%20a%20NavMesh%20-%20Transcript.txt)

## 1\.  Bake a NavMesh on the Ground GameObject.

- Select the **Ground** GameObject.
- In the **Inspector** window, select **Add Component** > **NavMeshSurface**.
- Select **Bake** in the **NavMeshSurface** component.


## 2\.  Configure what to include in the NavMesh surface.

- In the **Inspector** window, in the **NavMeshSurface** component settings,use the foldout (triangle) to expand the **Object Collection** module.
- Open the **Collect Objects** property dropdown menu and select **Current Object Hierarchy**.
- Select the **Bake** button again.
- The **PickUp** GameObject collectibles should now be ignored in the NavMesh.

![](https://connect-mediagw.unity.com/h1/20230921/learn/images/a5faecf5-81a3-4070-8718-f262525fccea_3-bake-navmesh.png)

## 4. Make the enemy chase the player

Follow the video or text instructions below to make the enemy, add a new script, and program the NavMesh Agent to chase the player:

[Video](https://connect-mediagw.unity.com/h1/20230828/videos/2bf4f303-2741-4c76-8ef8-24627aa82c2b_8.4_-_Make_the_enemy_chase_the_player.mp4)

[Download Transcript](https://connect-prd-cdn.unity.com/20230831/2d97b9de-23da-442e-8bb4-e9a12c448c00/8.4%20-%20Make%20the%20enemy%20chase%20the%20player%20-%20Transcript.txt)


## 1\.  Make the Enemy a NavMesh Agent.

- Select the **Enemy** GameObject in the **Hierarchy** window.
- In the **Inspector** window, select **Add Component** > **Nav Mesh Agent**.
- Set the **Speed** property to a value around **2.5**.


## 2\.  Add a new EnemyMovement script.

- With the **Enemy** GameObject selected in the **Hierarchy** window, select **Add Component** > **New script** in the **Inspector** window.
- Name your new script “EnemyMovement”.
- In the **Project** window, move the script from the root **Assets** folder into the **Scripts** folder.
- Open the new script for editing.


## 3\.  Add a variable to reference the Nav Mesh Agent component.

- Add the following “using” statement to the top of the script, right under the using UnityEngine line:

```csharp
using UnityEngine.AI;
```

- Above the **Start** function, add the following two new variables:

```csharp
public Transform player;
private NavMeshAgent navMeshAgent;
```

- In the **Start** function, add the following line of code to assign the **NavMeshAgent** variable:

```csharp
navMeshAgent = GetComponent<NavMeshAgent>();
```

## 4\.  Set the Enemy GameObject’s destination as the Player GameObject’s position.

- In the **Update** function, add the following code to update the **Enemy** GameObject’s destination to the **Player** GameObject:

```csharp
       if (player != null)
       {    
           navMeshAgent.SetDestination(player.position);
       }
```

## 5\.  Assign the player variable.

- Save the script and return to the Unity Editor.
- Select the **Enemy** GameObject in the **Hierarchy** Window, then drag the **Player** GameObject into the **Player** slot of the **EnemyMovement** script component in the **Inspector** window.

**Important:** This step is very important and easy to miss. If you do not do this step, you will see a **NullReferenceException** error in the **Console** window and your game will not work.

![](https://connect-mediagw.unity.com/h1/20230921/learn/images/67554b43-0719-42db-9b6a-8625c9a7db77_4-assign-player-variable.png)

## 6\.  Test the game.

- Save the scene and run the game.
- The **Enemy** GameObject should now chase the **Player** GameObject around.
- If it’s not working, you can check out the full script samples at the end of this tutorial.

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/6574a591-9f3e-4fc0-aaa1-124aa5428dbf_8_5.4.6-enemy-chasing-player.mp4)

## 5. Create static obstacles

Follow the video or text instructions below to create a variety of obstacles, include the obstacles in the NavMesh surface, and customize the agent settings:

[Video](https://connect-mediagw.unity.com/h1/20230906/videos/ad1a2bb9-1a40-4443-8a3e-6c304877ad3c_8.5_-_Create_static_obstacles.mp4)

[Download Transcript](https://connect-prd-cdn.unity.com/20230831/5d6b405b-b50d-4261-8c10-bbb81ff6682b/8.5%20-%20Create%20static%20obstacles%20-%20Transcript.txt)

## 1\.  Create a variety of obstacles.

- Create a new cube GameObject, then use the move, rotate, and scale tools to turn it into an interesting obstacle.
- Repeat this process to create additional obstacles of different shapes and sizes.
- Make sure to turn at least one object into a ramp to test your **Enemy** GameObject’s slope-climbing abilities.


## 2\.  Include the obstacles in the NavMesh Surface component.

- In the **Hierarchy** window, drag each obstacle GameObject onto the **Ground** GameObject to make them child GameObjects.
- Select the **Ground** GameObject and select **Bake** again in the **NavMesh Surface** component to regenerate the NavMesh with the updated obstacle configuration.
- You should now see the area around the obstacles carved out of the blue **NavMesh** **Surface** overlay in the scene.


## 3\.  Customize the agent settings.

- In the **NavMesh Surface** component, from the **Agent Type** dropdown, select **Open Agent Settings**. Alternatively, you can select **Window** > **AI** > **Navigation.**
- Increasing the step height will allow the agent to hop up onto higher surfaces.
- Increasing the max slope will allow the agent to climb up steeper hills.


![](https://connect-mediagw.unity.com/h1/20230921/learn/images/f20400ad-53e3-41b8-aefd-d014316a394c_5-agent-settings-for-obstacles.png)

## 4\.  Test your game

- Test your game and experiment with different agent settings.

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/99c8a4ac-6924-40e3-8dad-d06e3c876266_8_5.5.3-static-obstacles.mp4)

## 6. Create dynamic obstacles

Follow the video or text instructions below to create a light, movable cube, make the cube a NavMesh Obstacle, and turn it into a prefab:

[Video](https://connect-mediagw.unity.com/h1/20230828/videos/5856c0f7-9a17-4f4f-96e7-1786f5d177b6_8.6_-_Create_dynamic_obstacles.mp4)

[Download Transcript](https://connect-prd-cdn.unity.com/20230831/85d7f2ab-32f2-4477-a330-4908ec6398cd/8.6%20-%20Create%20dynamic%20obstacles%20-%20Transcript.txt)

## 1\.  Create a light, movable cube.

- Create a new cube GameObject and rename it to "DynamicBox".
- Scale and position the box to your liking in the scene.
- Create a new material named "Dynamic Obstacle", give it a color, and assign it to the new cube.
- In the **Inspector** window, add a new **Rigidbody** component, then reduce the **Mass** to around **0.1** so that it can be more easily pushed around.
- Test the scene and notice that the **Enemy** GameObject goes straight through the dynamic obstacle.


## 2\.  Make the cube a NavMesh Obstacle.

- Select the **DynamicBox** GameObject, then search for and add the **NavMesh Obstacle** component.
- Enable the **Carve** option in the **NavMesh Obstacle** component.


## 3\.  Turn it into a prefab.

- Drag the **DynamicBox** GameObject from the **Hierarchy** window into the **Prefabs** folder in the **Project** window. This will create a prefab of the **DynamicBox** GameObject.
- Duplicate and scatter the **DynamicBox** prefab instances around the play area as desired.

**Note:** You may want to create an empty parent object to hold all of these **DynamicBox** GameObjects to keep your **Hierarchy** window neat and organized.

![](https://connect-mediagw.unity.com/h1/20230921/learn/images/6af5ca47-5ecc-47bd-987d-bbde8d45eb25_6-navmesh-obstacle-carve.png)

## 4\.  Test your game.

- Experiment with different stacks of dynamic obstacles to make the most fun play area.

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/3f358782-4ce8-4fa0-9523-3b6f8ef65173_8_5.6.3-dynamic-obstacles.mp4)

## 7. Set the win and lose conditions

Follow the video or text instructions below to add a lose condition that destroys the player and says “You lose!”, add an “Enemy” tag to the **EnemyBody** GameObject, and destroy the **Enemy** GameObject when the player wins:

[Video](https://storage.googleapis.com/learn-platform-bucket-production/tutorial/10c82e88-34f5-544e-9e35-f01486e4baff/versions%5B_key==%225wZ4XsXcAZy0HxzXD45491%22%5D.sections%5B_key==%224efpH3AVCNp2JmxqIPVXmd%22%5D.body%5B_key==%224efpH3AVCNp2JmxqIPVXq1%22%5D.overviewVideo/8.7%20-%20Set%20the%20win%20and%20lose%20conditions_Fixed_20260601_151444.mp4) ([Transcript (en)](https://storage.googleapis.com/learn-platform-bucket-production/tutorial/10c82e88-34f5-544e-9e35-f01486e4baff/versions%5B_key==%225wZ4XsXcAZy0HxzXD45491%22%5D.sections%5B_key==%224efpH3AVCNp2JmxqIPVXmd%22%5D.body%5B_key==%224efpH3AVCNp2JmxqIPVXq1%22%5D.subtitles/8.7%20-%20Set%20the%20win%20and%20lose%20conditions_20260204_161859.srt))

[Download Transcript](https://connect-prd-cdn.unity.com/20230831/3b37cef2-7da9-4485-9ed4-4818af3d7b58/8.7%20-%20Set%20the%20win%20and%20lose%20conditions%20-%20Transcript.txt)

## 1\.  Add a lose condition that destroys the player and says “You lose!”

- Open the **PlayerController** script.
- Add the following new **OnCollisionEnter** function before the final curly bracket in the script:

```csharp
private void OnCollisionEnter(Collision collision)
{
   if (collision.gameObject.CompareTag("Enemy"))
   {
       // Destroy the current object
       Destroy(gameObject); 
       // Update the winText to display "You Lose!"
       winTextObject.gameObject.SetActive(true);
       winTextObject.GetComponent<TextMeshProUGUI>().text = "You Lose!";
   }
}
```

## 2\.  Add an “Enemy” tag to the EnemyBody GameObject.

- Save the script and return to the Unity Editor.
- Select the **EnemyBody** GameObject in the **Hierarchy** window.
- In the **Inspector** window, locate the **Tag** dropdown menu and select **Add Tag**.
- Select the **Add** (**+**) button to create a new tag and name it "Enemy" Make sure the capitalization matches what you wrote in your code.
- Save the new tag.
- In the **Inspector** window, select the **EnemyBody** GameObject again and set its tag to the newly created **Enemy** tag. Make sure you apply the tag to the **EnemyBody** child GameObject and not the **Enemy** parent GameObject.
- Run the game to test — now, when the **Enemy** GameObject collides with the player, the **Player** GameObject is destroyed and the updated text displays “You lose!”

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/c5161260-e62f-4dee-9751-c2765c5a0daa_8_5.7.3-you-lose-condition.mp4)

## 3\.  Destroy the Enemy GameObject when the player wins.

- Open the **PlayerController** script again.
- Inside the SetCountText function, within the if (count >= 12) condition, add the following line to destroy the **Enemy** GameObject:

```csharp
Destroy(GameObject.FindGameObjectWithTag("Enemy"));
```

## 4\.  Test your completed game.

- Save the script and return to the Editor.
- Run the game to test the win condition. When you collect all the **PickUp** GameObjects, the **Enemy** GameObject is destroyed.

[Video](https://connect-mediagw.unity.com/h1/20230921/videos/64cb6a97-fbbd-450e-ba5a-379ded983802_8_5.7.3-you-win-condition.mp4)

## 8. Final script samples _(Optional)_

If your scripts are not working as expected, below are examples of what your code should look like at this point. The comments have been added to make the code more readable.


## PlayerController.cs

```csharp
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;

public class PlayerController : MonoBehaviour
{
 // Rigidbody of the player.
 private Rigidbody rb; 

 // Variable to keep track of collected "PickUp" objects.
 private int count;

 // Movement along X and Y axes.
 private float movementX;
 private float movementY;

 // Speed at which the player moves.
 public float speed = 0;

 // UI text component to display count of "PickUp" objects collected.
 public TextMeshProUGUI countText;

 // UI object to display winning text.
 public GameObject winTextObject;

 // Start is called before the first frame update.
 void Start()
    {
 // Get and store the Rigidbody component attached to the player.
        rb = GetComponent<Rigidbody>();

 // Initialize count to zero.
        count = 0;

 // Update the count display.
        SetCountText();

 // Initially set the win text to be inactive.
        winTextObject.SetActive(false);
    }
 
 // This function is called when a move input is detected.
 void OnMove(InputValue movementValue)
    {
 // Convert the input value into a Vector2 for movement.
        Vector2 movementVector = movementValue.Get<Vector2>();

 // Store the X and Y components of the movement.
        movementX = movementVector.x; 
        movementY = movementVector.y; 
    }

 // FixedUpdate is called once per fixed frame-rate frame.
 void FixedUpdate() 
    {
 // Create a 3D movement vector using the X and Y inputs.
        Vector3 movement = new Vector3 (movementX, 0.0f, movementY);

 // Apply force to the Rigidbody to move the player.
        rb.AddForce(movement * speed); 
    }

 
 void OnTriggerEnter(Collider other) 
    {
 // Check if the object the player collided with has the "PickUp" tag.
 if (other.gameObject.CompareTag("PickUp")) 
        {
 // Deactivate the collided object (making it disappear).
            other.gameObject.SetActive(false);

 // Increment the count of "PickUp" objects collected.
            count = count + 1;

 // Update the count display.
            SetCountText();
        }
    }

 // Function to update the displayed count of "PickUp" objects collected.
 void SetCountText() 
    {
 // Update the count text with the current count.
        countText.text = "Count: " + count.ToString();

 // Check if the count has reached or exceeded the win condition.
 if (count >= 12)
        {
 // Display the win text.
            winTextObject.SetActive(true);

 // Destroy the enemy GameObject.
            Destroy(GameObject.FindGameObjectWithTag("Enemy"));
        }
    }

private void OnCollisionEnter(Collision collision)
{
 if (collision.gameObject.CompareTag("Enemy"))
    {
 // Destroy the current object
        Destroy(gameObject); 
 
 // Update the winText to display "You Lose!"
        winTextObject.gameObject.SetActive(true);
        winTextObject.GetComponent<TextMeshProUGUI>().text = "You Lose!";
 
    }

}


}
```

## EnemyMovement.cs

```csharp
using UnityEngine;
using UnityEngine.AI;

public class EnemyMovement : MonoBehaviour
{
 // Reference to the player's transform.
 public Transform player;

 // Reference to the NavMeshAgent component for pathfinding.
 private NavMeshAgent navMeshAgent;

 // Start is called before the first frame update.
 void Start()
    {
 // Get and store the NavMeshAgent component attached to this object.
        navMeshAgent = GetComponent<NavMeshAgent>();
    }

 // Update is called once per frame.
 void Update()
    {
 // If there's a reference to the player...
 if (player != null)
        {    
 // Set the enemy's destination to the player's current position.
            navMeshAgent.SetDestination(player.position);
        }
    }
}
```
