9
\$\begingroup\$

I'm currently making a prototype for a game I plan to develop. As far as I did, I managed to set up the navigation mesh and my navmeshagents.

I would like to display the path they are following when setDestination() is fired.

I did some researches but didn't find anything about it.

EDIT 1 : So I instantiate an empty object with a LineRenderer and I have a line bewteen my agent and the destination. Still I've not all the points when the path has to avoid an obstacle. Furthermore, I wonder if the agent.path does reflect the real path that the agent take as I noticed that it actually follow a "smoothier" path.

Here is the code so far :

GameObject container = new GameObject();
container.transform.parent = agent.gameObject.transform;
LineRenderer ligne = container.AddComponent<LineRenderer>();
ligne.SetColors(Color.white,Color.white);
ligne.SetWidth(0.1f,0.1f);
//Get def material

ligne.gameObject.renderer.material.color = Color.white;
ligne.gameObject.renderer.material.shader = Shader.Find("Sprites/Default");
ligne.gameObject.AddComponent<LineScript>();
ligne.SetVertexCount(agent.path.corners.Length+1);
int i = 0;
foreach(Vector3 v in p.corners)
{
    ligne.SetPosition(i,v);
    //Debug.Log("position agent"+g.transform.position);
    //Debug.Log("position corner = "+v);
    i++;
}
ligne.SetPosition(p.corners.Length,agent.destination);
ligne.gameObject.tag = "ligne";

So How can I get the real coordinates my agent is going to walk throught ?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Do you want to display it in game or just inside the Unity interface? \$\endgroup\$
    – nathan
    Dec 26 '13 at 17:54
  • \$\begingroup\$ It would be in game. I start to think that maybe I should use calculatePath() and get corners to manually instanciate texutre with dotted or dashed line, and a texture with a cross at the destination ... \$\endgroup\$
    – Sladix
    Dec 27 '13 at 8:45
12
\$\begingroup\$

It's actually really simple. First you put a line renderer component on your nav mesh agent object. If you notice, there is an array called positions. So if you attach the following script to your nav mesh agent, it will create a path between the nav mesh agent's origin and the destination.

var line : LineRenderer; //to hold the line Renderer
var target : Transform; //to hold the transform of the target
var agent : NavMeshAgent; //to hold the agent of this gameObject

function Start(){
    line = GetComponent(LineRenderer); //get the line renderer
    agent = GetComponent(NavMeshAgent); //get the agent
    getPath();
}

function getPath(){
    line.SetPosition(0, transform.position); //set the line's origin

    agent.SetDestination(target.position); //create the path
    yield WaitForEndOfFrame(); //wait for the path to generate

    DrawPath(agent.path);

    agent.Stop();//add this if you don't want to move the agent
}

function DrawPath(path : NavMeshPath){
    if(path.corners.Length < 2) //if the path has 1 or no corners, there is no need
        return;

    line.SetVertexCount(path.corners.Length); //set the array of positions to the amount of corners

    for(var i = 1; i < path.corners.Length; i++){
        line.SetPosition(i, path.corners[i]); //go through each corner and set that to the line renderer's position
    }
}

So that will create a path in the game view.

Hope this helps.

\$\endgroup\$
2
  • \$\begingroup\$ took me a while to realize this was Javascript and remember that Unity supported JS scripts, but this is still valid in C# (except from the function definition syntax) To be noted that as of 2018, LineRenderer supports SetPositions(), so you could just line.SetPositions(path.corners) \$\endgroup\$ Aug 28 '18 at 16:22
  • \$\begingroup\$ I was doing in C# and figured out that too, just did line.SetPositions(path.corners). Altho I want to draw these line on the mesh, any idea? \$\endgroup\$
    – Matheus
    Feb 19 '19 at 14:27
1
\$\begingroup\$

Ok I found a solution, Might not be the best but still a solution.

First, instantiate a game object with a line renderer and attach it to the agent :

NavMeshAgent agent = g.GetComponent<NavMeshAgent>();
agent.SetDestination (getDestination(hit.point+offset));
agent.CalculatePath(getDestination(hit.point+offset),agent.path);
GameObject container = new GameObject();
container.transform.position = agent.transform.position;
container.transform.parent = agent.gameObject.transform;

LineRenderer ligne = container.AddComponent<LineRenderer>();
ligne.SetColors(Color.white,Color.white);
ligne.SetWidth(0.1f,0.1f);
//Get def material
ligne.gameObject.renderer.material.color = Color.white;
ligne.gameObject.renderer.material.shader = Shader.Find("Sprites/Default");
ligne.gameObject.AddComponent<LineScript>();
ligne.gameObject.tag = "ligne";
ligne.enabled = false;

And then in the LineScript script :

float dist=this.transform.parent.GetComponent<NavMeshAgent>().remainingDistance;
if (dist != Mathf.Infinity && this.transform.parent.GetComponent<NavMeshAgent>().pathStatus == NavMeshPathStatus.PathComplete && this.transform.parent.GetComponent<NavMeshAgent>().remainingDistance == 0)
        Destroy (gameObject);

this.GetComponent<LineRenderer>().SetVertexCount(this.transform.parent.GetComponent<NavMeshAgent>().path.corners.Length);
int i = 0;
foreach(Vector3 v in this.transform.parent.GetComponent<NavMeshAgent>().path.corners)
{
    this.GetComponent<LineRenderer>().SetPosition(i,v);
    //Debug.Log("position agent"+g.transform.position);
    //Debug.Log("position corner = "+v);
    i++;
}
if (this.GetComponent<LineRenderer> ().enabled == false)
    this.GetComponent<LineRenderer> ().enabled = true;
\$\endgroup\$
1
  • \$\begingroup\$ I still got to handle multiples nav points \$\endgroup\$
    – Sladix
    Jan 9 '14 at 8:47
1
\$\begingroup\$
using UnityEngine;
using System.Collections;

public class PathUtils : MonoBehaviour {
private NavMeshAgent agent;
private Color c = Color.white;
public void Start() {
    agent = gameObject.GetComponent<NavMeshAgent> ();
}

public void Update() {
    StartCoroutine(DrawPath(agent.path));
}

IEnumerator DrawPath(NavMeshPath path) {
    yield return new WaitForEndOfFrame();
    path = agent.path;
    if (path.corners.Length < 2)
        return;
    switch (path.status) {
    case NavMeshPathStatus.PathComplete:
            c = Color.white;
            break;
    case NavMeshPathStatus.PathInvalid:
            c = Color.red;
            break;
    case NavMeshPathStatus.PathPartial:
            c = Color.yellow;
            break;
    }
            
    Vector3 previousCorner = path.corners[0];
    
    int i = 1;
    while (i < path.corners.Length) {
        Vector3 currentCorner = path.corners[i];
        Debug.DrawLine(previousCorner, currentCorner, c);
        previousCorner = currentCorner;
        i++;
    }
    
}
}

Edit: I had problems achieving this goal because the path.corner numbers were wrong. You have to wait until EndOfFrame otherwise you get an incomplete path.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Short explanation would be great. What does the code do? Also, edit your post to contain all the code in one code block. Thanks \$\endgroup\$
    – Katu
    Jul 18 '14 at 4:00
  • \$\begingroup\$ Seems more clean that my try ^^ But this will only work in the editor ... I wanted to draw the agent path ingame, and only the valid ones \$\endgroup\$
    – Sladix
    Jul 18 '14 at 9:34
  • \$\begingroup\$ This actually worked first try once I corrected the typo and missing "agent.path" argument in DrawPath (which I submitted as an edit). Don't see why it would only work in the editor, but it is fine for my needs either way \$\endgroup\$
    – Mike Wise
    Oct 21 '21 at 10:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .