Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Setting up navigation (AronGranburg A* scripts)

Discussion in 'Navigation' started by Corva-Nocta, Jan 5, 2016.

  1. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    I've been trying to find a good use of the A* pathfinding and found Aron Granburg's A* program, super great program and should be everything I need. However, I'm having a TON of trouble setting it up. I've been following the tutorials he has listed in his help files, but they do little more than set up the initial graph and placement of scripts. I've got the graph, I've got the scripts in the right place and they are all working as intended, now I need to take the next step and be able to actually control the player.

    Right now when I hit play the character moves to a designated location that is set beforehand, but I can't update the location as the game is playing. I would also like to change this to a click to move type of movement, but even there I am a bit stuck. How would I go about selecting a node nearest a mouse click? How would I update the path to go to the newest mouse click? I'm sure all these answers are located in the help files, or at least nearby, but for the life of me I can't seem to figure it out.

    Also smaller separate issue, when my character does find his way to the target location, he bounces and spins a bunch. It appears as though the player never stops moving once reaching his destination and keeps trying to adjust to hit the location. Odd?

    Any help at all would be great, thanks!
     
  2. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    You get a new path by calling the Seeker component, like this:
    Code (CSharp):
    1.  
    2. public void Seeker seeker;
    3.  
    4. seeker.StartPath(transform.position, target.position, OnPathComplete);
    5.  
    6. private void OnPathComplete(Path p)
    7.     {
    8.         path = p;
    9. }
    To get the nearest node:

    Code (CSharp):
    1. node = AstarPath.active.GetNearest(transform.position).node;
     
  3. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Ah ok perfect! Thanks! I'm assuming I put that first line of code all into an If statement, if (mousebuttondown) sort fo thing. That code to get the nearest node, super useful btw, is that going in the same place? I'm assuming yes, I'll try it and see what happens.
     
  4. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    Yeah, call StartPath when a button is clicked for example. I'm not sure how your system works but you can use the node for that, yes.
     
  5. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. //Note this line, if it is left out, the script won't know that the class 'Path' exists and it will throw compiler errors
    5. //This line should always be present at the top of scripts which use pathfinding
    6. using Pathfinding;
    7. public class AstarAI : MonoBehaviour
    8. {
    9.     //The point to move to
    10.     public Vector3 targetPosition;
    11.  
    12.     private Seeker seeker;
    13.     private CharacterController controller;
    14.  
    15.     //The calculated path
    16.     public Path path;
    17.  
    18.     //The AI's speed per second
    19.     public float speed = 100;
    20.  
    21.     //The max distance from the AI to a waypoint for it to continue to the next waypoint
    22.     public float nextWaypointDistance = 3;
    23.  
    24.     //The waypoint we are currently moving towards
    25.     private int currentWaypoint = 0;
    26.  
    27.     public float repathRate = 0.5f;
    28.     private float lastRepath = -9999;
    29.  
    30.     public void Start()
    31.     {
    32.         seeker = GetComponent<Seeker>();
    33.         controller = GetComponent<CharacterController>();
    34.  
    35.         //Start a new path to the targetPosition, return the result to the OnPathComplete function
    36.         //seeker.StartPath (transform.position,targetPosition, OnPathComplete);
    37.     }
    38.  
    39.     public void OnPathComplete(Path p)
    40.     {
    41.         p.Claim(this);
    42.         if (!p.error)
    43.         {
    44.             if (path != null) path.Release(this);
    45.             path = p;
    46.             //Reset the waypoint counter
    47.             currentWaypoint = 0;
    48.         }
    49.         else
    50.         {
    51.             p.Release(this);
    52.             Debug.Log("Oh noes, the target was not reachable: " + p.errorLog);
    53.         }
    54.  
    55.         //seeker.StartPath (transform.position,targetPosition, OnPathComplete);
    56.     }
    57.  
    58.     public void Update()
    59.     {
    60.         if (Time.time - lastRepath > repathRate && seeker.IsDone())
    61.         {
    62.             lastRepath = Time.time + Random.value * repathRate * 0.5f;
    63.             seeker.StartPath(transform.position, targetPosition, OnPathComplete);
    64.         }
    65.  
    66.         if (path == null)
    67.         {
    68.             //We have no path to move after yet
    69.             return;
    70.         }
    71.  
    72.         if (currentWaypoint > path.vectorPath.Count) return;
    73.         if (currentWaypoint == path.vectorPath.Count)
    74.         {
    75.             Debug.Log("End Of Path Reached");
    76.             currentWaypoint++;
    77.             return;
    78.         }
    79.  
    80.         //Direction to the next waypoint
    81.         Vector3 dir = (path.vectorPath[currentWaypoint] - transform.position).normalized;
    82.         dir *= speed;// * Time.deltaTime;
    83.         //transform.Translate (dir);
    84.         controller.SimpleMove(dir);
    85.  
    86.         //if (Vector3.Distance (transform.position,path.vectorPath[currentWaypoint]) < nextWaypointDistance) {
    87.         if ((transform.position - path.vectorPath[currentWaypoint]).sqrMagnitude < nextWaypointDistance * nextWaypointDistance)
    88.         {
    89.             currentWaypoint++;
    90.             return;
    91.         }
    92.     }
    93. }
    So this the whole script, sorry for such a long reply with this. Trying to get the script you mentioned to function properly, unfortunately don't know enough about programming. Tried sticking it in a few places but it seems some of the references are incorrect (like the "node") so I need to change the names of them. I can't quite figure out which part of the code I need to change it too though, seems difficult to switch the code over.

    All of this script was downloaded through the asset store. I am trying to wrap my head around pathfinding and thought this would be a good place to start. It works very well, but getting it to work with click to move is a little harder. Of course if there is a simpler way to do the pathfinding I am all ears! Especially if it means I can understand it!
     
    Last edited: Jan 10, 2016
  6. PhoenixRising1

    PhoenixRising1

    Joined:
    Sep 12, 2015
    Posts:
    488
    I would only search for a new path when the mouse is clicked, no reason in doing it otherwise. Use a raycast to get the position (destination).
     
  7. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Smart. It all seems to work! Thanks so much for your help.

    I put the whole func update into the if(getbuttondown) script. And added an update to the target position with raycasting. Now just have to make all the movement stay on the grid and with the nodes. Gonna figure out how to add that line you mentioned to find the nearest node.