Unity Learn home
View Tutorial Content
Steps

Runtime NavMesh Generation

Tutorial
Beginner
+0 XP
1 Hour
(105)
Summary
In this recorded live training session we show how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls.
Select your Unity version
Last updated: May 03, 2023
2017.1
Language
English

1.Introduction and Navigation Overview

In this live training session we will learn how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls.
In this session we will introduce the session and get an overview of the Navigation system.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
Type caption for embed (optional)

DirectedAgent

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class DirectedAgent : MonoBehaviour { private NavMeshAgent agent; // Use this for initialization void Awake () { agent = GetComponent<NavMeshAgent> (); } public void MoveToLocation(Vector3 targetPoint) { agent.destination = targetPoint; agent.isStopped = false; } }

RaycastDestinationSetter

using UnityEngine; using System.Collections; public class RaycastDestinationSetter : MonoBehaviour { public float fireRate = 0.25f; // Number in seconds which controls how often the player can fire public float weaponRange = 500f; // Distance in Unity units over which the player can fire public Transform gunEnd; // Holds a reference to the gun end object, marking the muzzle location of the gun public DirectedAgent directedAgent; private Camera fpsCam; // Holds a reference to the first person camera private WaitForSeconds shotDuration = new WaitForSeconds(0.07f); // WaitForSeconds object used by our ShotEffect coroutine, determines time laser line will remain visible private AudioSource gunAudio; // Reference to the audio source which will play our shooting sound effect private LineRenderer laserLine; // Reference to the LineRenderer component which will display our laserline private float nextFire; // Float to store the time the player will be allowed to fire again, after firing void Start () { // Get and store a reference to our LineRenderer component laserLine = GetComponent<LineRenderer>(); // Get and store a reference to our AudioSource component gunAudio = GetComponent<AudioSource>(); // Get and store a reference to our Camera by searching this GameObject and its parents fpsCam = GetComponentInParent<Camera>(); } void Update () { // Check if the player has pressed the fire button and if enough time has elapsed since they last fired if (Input.GetButtonDown("Fire1") && Time.time > nextFire) { // Update the time when our player can fire next nextFire = Time.time + fireRate; // Start our ShotEffect coroutine to turn our laser line on and off StartCoroutine (ShotEffect()); // Create a vector at the center of our camera's viewport Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f)); // Declare a raycast hit to store information about what our raycast has hit RaycastHit hit; // Set the start position for our visual effect for our laser to the position of gunEnd laserLine.SetPosition (0, gunEnd.position); // Check if our raycast has hit anything if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange)) { // Set the end position for our laser line laserLine.SetPosition (1, hit.point); directedAgent.MoveToLocation (hit.point); } else { // If we did not hit anything, set the end of the line to a position directly in front of the camera at the distance of weaponRange laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange)); } } } private IEnumerator ShotEffect() { // Play the shooting sound effect gunAudio.Play (); // Turn on our line renderer laserLine.enabled = true; //Wait for .07 seconds yield return shotDuration; // Deactivate our line renderer after waiting laserLine.enabled = false; } }

NavigationBaker

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavigationBaker : MonoBehaviour { public NavMeshSurface[] surfaces; public Transform[] objectsToRotate; // Use this for initialization void Start () { for (int j = 0; j < objectsToRotate.Length; j++) { objectsToRotate [j].localRotation = Quaternion.Euler (new Vector3 (0, Random.Range (0, 360), 0)); } for (int i = 0; i < surfaces.Length; i++) { surfaces [i].BuildNavMesh (); } } }

2.The NavMeshSurface Component

In this live training session we will learn how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls. In this session we will learn how to bake NavMeshes using the NavMeshSurface and how to set up multiple agent types if needed.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
Type caption for embed (optional)

DirectedAgent

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class DirectedAgent : MonoBehaviour { private NavMeshAgent agent; // Use this for initialization void Awake () { agent = GetComponent<NavMeshAgent> (); } public void MoveToLocation(Vector3 targetPoint) { agent.destination = targetPoint; agent.isStopped = false; } }

RaycastDestinationSetter

using UnityEngine; using System.Collections; public class RaycastDestinationSetter : MonoBehaviour { public float fireRate = 0.25f; // Number in seconds which controls how often the player can fire public float weaponRange = 500f; // Distance in Unity units over which the player can fire public Transform gunEnd; // Holds a reference to the gun end object, marking the muzzle location of the gun public DirectedAgent directedAgent; private Camera fpsCam; // Holds a reference to the first person camera private WaitForSeconds shotDuration = new WaitForSeconds(0.07f); // WaitForSeconds object used by our ShotEffect coroutine, determines time laser line will remain visible private AudioSource gunAudio; // Reference to the audio source which will play our shooting sound effect private LineRenderer laserLine; // Reference to the LineRenderer component which will display our laserline private float nextFire; // Float to store the time the player will be allowed to fire again, after firing void Start () { // Get and store a reference to our LineRenderer component laserLine = GetComponent<LineRenderer>(); // Get and store a reference to our AudioSource component gunAudio = GetComponent<AudioSource>(); // Get and store a reference to our Camera by searching this GameObject and its parents fpsCam = GetComponentInParent<Camera>(); } void Update () { // Check if the player has pressed the fire button and if enough time has elapsed since they last fired if (Input.GetButtonDown("Fire1") && Time.time > nextFire) { // Update the time when our player can fire next nextFire = Time.time + fireRate; // Start our ShotEffect coroutine to turn our laser line on and off StartCoroutine (ShotEffect()); // Create a vector at the center of our camera's viewport Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f)); // Declare a raycast hit to store information about what our raycast has hit RaycastHit hit; // Set the start position for our visual effect for our laser to the position of gunEnd laserLine.SetPosition (0, gunEnd.position); // Check if our raycast has hit anything if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange)) { // Set the end position for our laser line laserLine.SetPosition (1, hit.point); directedAgent.MoveToLocation (hit.point); } else { // If we did not hit anything, set the end of the line to a position directly in front of the camera at the distance of weaponRange laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange)); } } } private IEnumerator ShotEffect() { // Play the shooting sound effect gunAudio.Play (); // Turn on our line renderer laserLine.enabled = true; //Wait for .07 seconds yield return shotDuration; // Deactivate our line renderer after waiting laserLine.enabled = false; } }

NavigationBaker

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavigationBaker : MonoBehaviour { public NavMeshSurface[] surfaces; public Transform[] objectsToRotate; // Use this for initialization void Start () { for (int j = 0; j < objectsToRotate.Length; j++) { objectsToRotate [j].localRotation = Quaternion.Euler (new Vector3 (0, Random.Range (0, 360), 0)); } for (int i = 0; i < surfaces.Length; i++) { surfaces [i].BuildNavMesh (); } } }

3.Walking On Walls and Ceilings

In this live training session we will learn how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls. In this session we will learn how to use NavMesh to allow agents to walk on walls, ceilings or other rotated surfaces.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
Type caption for embed (optional)

DirectedAgent

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class DirectedAgent : MonoBehaviour { private NavMeshAgent agent; // Use this for initialization void Awake () { agent = GetComponent<NavMeshAgent> (); } public void MoveToLocation(Vector3 targetPoint) { agent.destination = targetPoint; agent.isStopped = false; } }

RaycastDestinationSetter

using UnityEngine; using System.Collections; public class RaycastDestinationSetter : MonoBehaviour { public float fireRate = 0.25f; // Number in seconds which controls how often the player can fire public float weaponRange = 500f; // Distance in Unity units over which the player can fire public Transform gunEnd; // Holds a reference to the gun end object, marking the muzzle location of the gun public DirectedAgent directedAgent; private Camera fpsCam; // Holds a reference to the first person camera private WaitForSeconds shotDuration = new WaitForSeconds(0.07f); // WaitForSeconds object used by our ShotEffect coroutine, determines time laser line will remain visible private AudioSource gunAudio; // Reference to the audio source which will play our shooting sound effect private LineRenderer laserLine; // Reference to the LineRenderer component which will display our laserline private float nextFire; // Float to store the time the player will be allowed to fire again, after firing void Start () { // Get and store a reference to our LineRenderer component laserLine = GetComponent<LineRenderer>(); // Get and store a reference to our AudioSource component gunAudio = GetComponent<AudioSource>(); // Get and store a reference to our Camera by searching this GameObject and its parents fpsCam = GetComponentInParent<Camera>(); } void Update () { // Check if the player has pressed the fire button and if enough time has elapsed since they last fired if (Input.GetButtonDown("Fire1") && Time.time > nextFire) { // Update the time when our player can fire next nextFire = Time.time + fireRate; // Start our ShotEffect coroutine to turn our laser line on and off StartCoroutine (ShotEffect()); // Create a vector at the center of our camera's viewport Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f)); // Declare a raycast hit to store information about what our raycast has hit RaycastHit hit; // Set the start position for our visual effect for our laser to the position of gunEnd laserLine.SetPosition (0, gunEnd.position); // Check if our raycast has hit anything if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange)) { // Set the end position for our laser line laserLine.SetPosition (1, hit.point); directedAgent.MoveToLocation (hit.point); } else { // If we did not hit anything, set the end of the line to a position directly in front of the camera at the distance of weaponRange laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange)); } } } private IEnumerator ShotEffect() { // Play the shooting sound effect gunAudio.Play (); // Turn on our line renderer laserLine.enabled = true; //Wait for .07 seconds yield return shotDuration; // Deactivate our line renderer after waiting laserLine.enabled = false; } }

NavigationBaker

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavigationBaker : MonoBehaviour { public NavMeshSurface[] surfaces; public Transform[] objectsToRotate; // Use this for initialization void Start () { for (int j = 0; j < objectsToRotate.Length; j++) { objectsToRotate [j].localRotation = Quaternion.Euler (new Vector3 (0, Random.Range (0, 360), 0)); } for (int i = 0; i < surfaces.Length; i++) { surfaces [i].BuildNavMesh (); } } }

4.Setting NavMeshAgent Destination

In this live training session we will learn how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls. In this session we will learn how to write scripts to set and control the destination of a NavMeshAgent.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
Type caption for embed (optional)

DirectedAgent

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class DirectedAgent : MonoBehaviour { private NavMeshAgent agent; // Use this for initialization void Awake () { agent = GetComponent<NavMeshAgent> (); } public void MoveToLocation(Vector3 targetPoint) { agent.destination = targetPoint; agent.isStopped = false; } }

RaycastDestinationSetter

using UnityEngine; using System.Collections; public class RaycastDestinationSetter : MonoBehaviour { public float fireRate = 0.25f; // Number in seconds which controls how often the player can fire public float weaponRange = 500f; // Distance in Unity units over which the player can fire public Transform gunEnd; // Holds a reference to the gun end object, marking the muzzle location of the gun public DirectedAgent directedAgent; private Camera fpsCam; // Holds a reference to the first person camera private WaitForSeconds shotDuration = new WaitForSeconds(0.07f); // WaitForSeconds object used by our ShotEffect coroutine, determines time laser line will remain visible private AudioSource gunAudio; // Reference to the audio source which will play our shooting sound effect private LineRenderer laserLine; // Reference to the LineRenderer component which will display our laserline private float nextFire; // Float to store the time the player will be allowed to fire again, after firing void Start () { // Get and store a reference to our LineRenderer component laserLine = GetComponent<LineRenderer>(); // Get and store a reference to our AudioSource component gunAudio = GetComponent<AudioSource>(); // Get and store a reference to our Camera by searching this GameObject and its parents fpsCam = GetComponentInParent<Camera>(); } void Update () { // Check if the player has pressed the fire button and if enough time has elapsed since they last fired if (Input.GetButtonDown("Fire1") && Time.time > nextFire) { // Update the time when our player can fire next nextFire = Time.time + fireRate; // Start our ShotEffect coroutine to turn our laser line on and off StartCoroutine (ShotEffect()); // Create a vector at the center of our camera's viewport Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f)); // Declare a raycast hit to store information about what our raycast has hit RaycastHit hit; // Set the start position for our visual effect for our laser to the position of gunEnd laserLine.SetPosition (0, gunEnd.position); // Check if our raycast has hit anything if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange)) { // Set the end position for our laser line laserLine.SetPosition (1, hit.point); directedAgent.MoveToLocation (hit.point); } else { // If we did not hit anything, set the end of the line to a position directly in front of the camera at the distance of weaponRange laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange)); } } } private IEnumerator ShotEffect() { // Play the shooting sound effect gunAudio.Play (); // Turn on our line renderer laserLine.enabled = true; //Wait for .07 seconds yield return shotDuration; // Deactivate our line renderer after waiting laserLine.enabled = false; } }

NavigationBaker

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavigationBaker : MonoBehaviour { public NavMeshSurface[] surfaces; public Transform[] objectsToRotate; // Use this for initialization void Start () { for (int j = 0; j < objectsToRotate.Length; j++) { objectsToRotate [j].localRotation = Quaternion.Euler (new Vector3 (0, Random.Range (0, 360), 0)); } for (int i = 0; i < surfaces.Length; i++) { surfaces [i].BuildNavMesh (); } } }

5.Baking NavMesh at Runtime

In this live training session we will learn how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls. In this session we will learn how to bake NavMeshes at runtime, including for procedural style levels.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
Type caption for embed (optional)

DirectedAgent

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class DirectedAgent : MonoBehaviour { private NavMeshAgent agent; // Use this for initialization void Awake () { agent = GetComponent<NavMeshAgent> (); } public void MoveToLocation(Vector3 targetPoint) { agent.destination = targetPoint; agent.isStopped = false; } }

RaycastDestinationSetter

using UnityEngine; using System.Collections; public class RaycastDestinationSetter : MonoBehaviour { public float fireRate = 0.25f; // Number in seconds which controls how often the player can fire public float weaponRange = 500f; // Distance in Unity units over which the player can fire public Transform gunEnd; // Holds a reference to the gun end object, marking the muzzle location of the gun public DirectedAgent directedAgent; private Camera fpsCam; // Holds a reference to the first person camera private WaitForSeconds shotDuration = new WaitForSeconds(0.07f); // WaitForSeconds object used by our ShotEffect coroutine, determines time laser line will remain visible private AudioSource gunAudio; // Reference to the audio source which will play our shooting sound effect private LineRenderer laserLine; // Reference to the LineRenderer component which will display our laserline private float nextFire; // Float to store the time the player will be allowed to fire again, after firing void Start () { // Get and store a reference to our LineRenderer component laserLine = GetComponent<LineRenderer>(); // Get and store a reference to our AudioSource component gunAudio = GetComponent<AudioSource>(); // Get and store a reference to our Camera by searching this GameObject and its parents fpsCam = GetComponentInParent<Camera>(); } void Update () { // Check if the player has pressed the fire button and if enough time has elapsed since they last fired if (Input.GetButtonDown("Fire1") && Time.time > nextFire) { // Update the time when our player can fire next nextFire = Time.time + fireRate; // Start our ShotEffect coroutine to turn our laser line on and off StartCoroutine (ShotEffect()); // Create a vector at the center of our camera's viewport Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f)); // Declare a raycast hit to store information about what our raycast has hit RaycastHit hit; // Set the start position for our visual effect for our laser to the position of gunEnd laserLine.SetPosition (0, gunEnd.position); // Check if our raycast has hit anything if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange)) { // Set the end position for our laser line laserLine.SetPosition (1, hit.point); directedAgent.MoveToLocation (hit.point); } else { // If we did not hit anything, set the end of the line to a position directly in front of the camera at the distance of weaponRange laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange)); } } } private IEnumerator ShotEffect() { // Play the shooting sound effect gunAudio.Play (); // Turn on our line renderer laserLine.enabled = true; //Wait for .07 seconds yield return shotDuration; // Deactivate our line renderer after waiting laserLine.enabled = false; } }

NavigationBaker

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavigationBaker : MonoBehaviour { public NavMeshSurface[] surfaces; public Transform[] objectsToRotate; // Use this for initialization void Start () { for (int j = 0; j < objectsToRotate.Length; j++) { objectsToRotate [j].localRotation = Quaternion.Euler (new Vector3 (0, Random.Range (0, 360), 0)); } for (int i = 0; i < surfaces.Length; i++) { surfaces [i].BuildNavMesh (); } } }

6.Questions and Answers

In this live training session we will learn how to work with Unity’s Navigation tools at runtime. We will explore the publicly available Components for Runtime NavMesh Building and look at how we can use the provided components to create characters which can navigate dynamic environments and walk on arbitrarily rotated surfaces, including enemies that walk on walls. In this session we will learn how to bake NavMeshes at runtime, including for procedural style levels.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
Type caption for embed (optional)

DirectedAgent

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class DirectedAgent : MonoBehaviour { private NavMeshAgent agent; // Use this for initialization void Awake () { agent = GetComponent<NavMeshAgent> (); } public void MoveToLocation(Vector3 targetPoint) { agent.destination = targetPoint; agent.isStopped = false; } }

RaycastDestinationSetter

using UnityEngine; using System.Collections; public class RaycastDestinationSetter : MonoBehaviour { public float fireRate = 0.25f; // Number in seconds which controls how often the player can fire public float weaponRange = 500f; // Distance in Unity units over which the player can fire public Transform gunEnd; // Holds a reference to the gun end object, marking the muzzle location of the gun public DirectedAgent directedAgent; private Camera fpsCam; // Holds a reference to the first person camera private WaitForSeconds shotDuration = new WaitForSeconds(0.07f); // WaitForSeconds object used by our ShotEffect coroutine, determines time laser line will remain visible private AudioSource gunAudio; // Reference to the audio source which will play our shooting sound effect private LineRenderer laserLine; // Reference to the LineRenderer component which will display our laserline private float nextFire; // Float to store the time the player will be allowed to fire again, after firing void Start () { // Get and store a reference to our LineRenderer component laserLine = GetComponent<LineRenderer>(); // Get and store a reference to our AudioSource component gunAudio = GetComponent<AudioSource>(); // Get and store a reference to our Camera by searching this GameObject and its parents fpsCam = GetComponentInParent<Camera>(); } void Update () { // Check if the player has pressed the fire button and if enough time has elapsed since they last fired if (Input.GetButtonDown("Fire1") && Time.time > nextFire) { // Update the time when our player can fire next nextFire = Time.time + fireRate; // Start our ShotEffect coroutine to turn our laser line on and off StartCoroutine (ShotEffect()); // Create a vector at the center of our camera's viewport Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f)); // Declare a raycast hit to store information about what our raycast has hit RaycastHit hit; // Set the start position for our visual effect for our laser to the position of gunEnd laserLine.SetPosition (0, gunEnd.position); // Check if our raycast has hit anything if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange)) { // Set the end position for our laser line laserLine.SetPosition (1, hit.point); directedAgent.MoveToLocation (hit.point); } else { // If we did not hit anything, set the end of the line to a position directly in front of the camera at the distance of weaponRange laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange)); } } } private IEnumerator ShotEffect() { // Play the shooting sound effect gunAudio.Play (); // Turn on our line renderer laserLine.enabled = true; //Wait for .07 seconds yield return shotDuration; // Deactivate our line renderer after waiting laserLine.enabled = false; } }

NavigationBaker

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavigationBaker : MonoBehaviour { public NavMeshSurface[] surfaces; public Transform[] objectsToRotate; // Use this for initialization void Start () { for (int j = 0; j < objectsToRotate.Length; j++) { objectsToRotate [j].localRotation = Quaternion.Euler (new Vector3 (0, Random.Range (0, 360), 0)); } for (int i = 0; i < surfaces.Length; i++) { surfaces [i].BuildNavMesh (); } } }

Runtime NavMesh Generation
Runtime NavMesh Generation
General Tutorial Discussion
0
1
1. Introduction and Navigation Overview
0
0
2. The NavMeshSurface Component
0
0
3. Walking On Walls and Ceilings
0
0
4. Setting NavMeshAgent Destination
0
0
5. Baking NavMesh at Runtime
1
3
6. Questions and Answers
0
0