5
\$\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\$
  • 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
7
\$\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\$
  • \$\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\$ – FacelessPanda 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 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\$
  • \$\begingroup\$ I still got to handle multiples nav points \$\endgroup\$ – Sladix Jan 9 '14 at 8:47
0
\$\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() {
    StartCouroutine(DrawPath());
}

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\$
  • 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.