Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Draw navigation line between player and goal

Discussion in 'Navigation' started by qqepijackxu, Jun 14, 2019.

  1. qqepijackxu

    qqepijackxu

    Joined:
    Jun 14, 2019
    Posts:
    12
    Hi. I'm more 3d-modeler than coder and i'm doing this scene where are few important places and I want to have some navigation lines that would show the path to player (prefer lines not going through the walls). I'm thinking something like Dead Spaces deck nav where laserline shows path to objective goal. I'm using linerenderer and navmesh. With this simple code:


    Code (CSharp):
    1.  
    2. public Transform goal;
    3.     void Start()
    4.     {
    5.      
    6.         UnityEngine.AI.NavMeshAgent navline = GetComponent<UnityEngine.AI.NavMeshAgent>();
    7.         navline.destination = goal.position;
    8.     }
    9.  
    10.  
    11. }
    12.  
    It shoots the line to target and stays wobbling there. But how to do line between player and goal?

    EDIT: something like this:

     
    Last edited: Jun 15, 2019
  2. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    431
    You don't need to put the NavmeshAgent on the same object as the Line Renderer, because that will move the line renderer object.
    What you want to do instead is calculate the path between the player and destination, and draw the path in the LineRenderer by taking the path's corners.
    Pseudocode:
    Code (CSharp):
    1. NavMeshPath path;
    2. NavMesh.CalculatePath(player, destination, path); //Saves the path in the path variable.
    3. Vector3[] corners = path.corners;
    4. lineRenderer.SetPositions(corners);
    5.  
     
  3. qqepijackxu

    qqepijackxu

    Joined:
    Jun 14, 2019
    Posts:
    12
    Thank you so much! I got it working.
     
  4. denholmspurr

    denholmspurr

    Joined:
    Apr 17, 2020
    Posts:
    42
    Having the same issue. Would love to know how you fixed it as I can't get my head round the suggested edit :/
     
  5. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    431
    I never wrote the actual code, this snippet simply explained the idea on how to solve the problem.
    You basically want to have a separate object that is NOT parented to the player draw the line for your path.
    To do so, you use a LineRenderer Component which draws lines between points you feed it.
    Then you set the points of this linerenderer as the corners of the NavMeshPath you calculate when the player starts moving.
     
  6. denholmspurr

    denholmspurr

    Joined:
    Apr 17, 2020
    Posts:
    42
    Ah, see I'm working in 2D so I don't think I can use the NavMeshPath?

    I have an AI Path script that I've created attached to a gameObject, which creates a Gizmo line to a target. The target moves quite often and the path is adjusted. That all works fine.

    What I want is to draw a line along that path up to a certain distance away from the gameObject, and have that constantly update.

    Something like the red expanding line in this, the eventual target being off the screen to the left:


    Completely stumped on how to achieve this. I have a line renderer component attached but I can't for the life of me work out how to make it draw along that line.
     
  7. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    431
    Just set the corners of your path as points in your LineRenderer.
    Or am I missing something here?
     
  8. denholmspurr

    denholmspurr

    Joined:
    Apr 17, 2020
    Posts:
    42
    I think I am is the problem. Forgive my royal noobness!

    How do i find the corners of my path and set them as points?
     
  9. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    431
    Well that depends on that AI Path system of yours. Unity's default pathing allows you to get the corners of its paths like this, if you're using another pathing system you'll have to see if they provide something like that as well, but I can't know that without specifically knowing what you're using.
     
  10. denholmspurr

    denholmspurr

    Joined:
    Apr 17, 2020
    Posts:
    42
    Ah ok sorry yes let me be clearer.

    I'm using A* pathfinding grid with a custom script. The grid updates every 6f and target moves every 4f.

    Here's a few pics of the game view:





    The green lines are obvs gizmos of the path. How would I draw a line that continually updates along that path up to a certain distance like the example above? I'm not sure how I suss out the corners of that path?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Pathfinding;
    5.  
    6. public class HurricaneAI : MonoBehaviour
    7. {
    8.  
    9.     public Transform target;
    10.     public float speed = 200f;
    11.     public float nextWaypointDistance = 5f;
    12.     float force = 5f;
    13.  
    14.     Path path;
    15.     int currentWaypoint = 0;
    16.     bool reachedEndOfPath = false;
    17.  
    18.     Seeker seeker;
    19.     Rigidbody2D rb;
    20.  
    21.     // Start is called before the first frame update
    22.     void Start()
    23.     {
    24.  
    25.         seeker = GetComponent<Seeker>();
    26.         rb = GetComponent<Rigidbody2D>();
    27.  
    28.         InvokeRepeating("UpdatePath", 0f, .5f);
    29.     }
    30.     void UpdatePath()
    31.     {
    32.         if (seeker.IsDone())
    33.         seeker.StartPath(rb.position, target.position, OnPathComplete);
    34.     }
    35.  
    36.  
    37.  
    38.     void OnPathComplete(Path p)
    39.  
    40.     {
    41.         if(!p.error)
    42.         {
    43.             path = p;
    44.             currentWaypoint = 0;
    45.         }
    46.     }
    47.  
    48.     // Update is called once per frame
    49.     void FixedUpdate()
    50.     {
    51.         if (path == null)
    52.             return;
    53.  
    54.         if (currentWaypoint >= path.vectorPath.Count)
    55.         {
    56.             reachedEndOfPath = true;
    57.             return;
    58.  
    59.         } else
    60.         {
    61.             reachedEndOfPath = false;
    62.         }
    63.  
    64.         Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
    65.         Vector2 force = direction * speed * Time.deltaTime;
    66.  
    67.         rb.AddForce(force);
    68.  
    69.         float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
    70.  
    71.         if (distance < nextWaypointDistance)
    72.         {
    73.             currentWaypoint++;
    74.         }
    75.     }
    76.     // C#
    77.     // adjust to your needs
    78.  
    79. }
    80.  
    81. }
    82.  
     
  11. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    431
    From the looks of it your corners are going to be in path.vectorPath, that's an array of vectors and considering you calculate your direction by subtracting your current position from those, they have to be positions.

    So you just take that array and set all its points into your LineRenderer.
    If you only want to draw up to a certain distance, you'll have to stop setting points into your renderer as soon as you reach your treshold distance. This is simply checked by subtracting the distance between the two points you draw in each step. In case your last point falls between two path corners, your last point will be last corner + (next corner - last corner).normalized * remainingDistance.
     
  12. denholmspurr

    denholmspurr

    Joined:
    Apr 17, 2020
    Posts:
    42
    Ok so it is possible! Thanks reassuring that I'm not going completely insane with this.

    I haven't fully understood everything you've said but I think can have a go at working it out, thank you.

    In theory, i could I cache those corners in that AI script?

    So create the following:

    Code (CSharp):
    1. public Vector2 waypoint1;
    2. public Vector2 waypoint2;
    3. public Vector2 waypoint3;
    4. public Vector2 waypoint4;
    5. public Vector2 waypoint5;
    6. public Vector2 waypoint6;
     
  13. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    431
    You could, yes, but you already have an array which is much more useful since you don't have to declare a cache for each separate vector. All you need to do is figure out which points from that array you want in your linerenderer, and copy them over to the linerenderer's positions array.

    Code (CSharp):
    1. path.vectorPath;
    2. //Figure out the first point you want to draw, store the index
    3. int firstIndex;
    4. //Figure out how many of the following points you want to draw, that will be based on your distance
    5. int length;
    6. //Copy it all over, copy from path.vectorPath to lineRenderer.positions, starting from firstIndex copy length amount of entries. We want the entries to start at index 0 in lineRenderer.positions, so we put a 0 for the destination Index
    7. Array.Copy(path.vectorPath, firstIndex, lineRenderer.positions, 0, length);
    8.  
    Mind you, you might have to do some extra initialisation for this copy code to work. Google it if you get problems.
    In case you want to draw a point between two points of your path, you'll have to calculate it and then add it after doing the copy manually.
     
  14. denholmspurr

    denholmspurr

    Joined:
    Apr 17, 2020
    Posts:
    42

    Thank you, I'll give this a try and check back in if I'm having troubles!
     
  15. Sixtofivedream

    Sixtofivedream

    Joined:
    Jun 13, 2015
    Posts:
    1
unityunity