Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

A* plugin generates empty paths when asked to route to the cursor location. Help!

Discussion in 'Scripting' started by AidanofVT, May 26, 2020.

  1. AidanofVT

    AidanofVT

    Joined:
    Nov 10, 2019
    Posts:
    104
    It's a top-down RTS-style interface in a 2d environment. I'm trying to get it so that when the background (represented by a quad with a mesh collider) gets clicked on, the selected units move to the cursor location, while if a unit gets clicked on, the selected units move to the location of the clicked unit:

    From the unit script:
    Code (CSharp):
    1.     void OnMouseOver() {
    2.         if (Input.GetKeyDown(KeyCode.Mouse0)) {
    3.             Debug.Log("Click Registered.");
    4.             gameState.addActiveUnit(gameObject);
    5.             highlight();
    6.         }
    7.         else if (Input.GetKeyDown(KeyCode.Mouse1)) {
    8.             Debug.Log("Right clicked.");
    9.             driver.thingRightClicked(gameObject);
    10.             Debug.Log("Called Driver");
    11.         }
    12.     }
    From the ground script:
    Code (CSharp):
    1.     private void OnMouseOver() {
    2.         if (Input.GetKeyDown(KeyCode.Mouse0)) {
    3.             Debug.Log("Click Registered.");
    4.             driver.clearActiveUnits();
    5.         }
    6.         else if (Input.GetKeyDown(KeyCode.Mouse1)) {
    7.             Debug.Log("Right clicked.");
    8.             driver.thingRightClicked(gameObject);
    9.             Debug.Log("Called Driver");
    10.         }
    11.     }
    From the driver script:
    Code (CSharp):
    1.     public void thingRightClicked (GameObject thingClicked) {
    2.         Vector3 destination;
    3.         switch (thingClicked.tag) {
    4.             case "unit":
    5.                 destination = thingClicked.transform.position;
    6.                 break;
    7.             case "ground":
    8.                 destination = Input.mousePosition;
    9.                 break;
    10.             default:
    11.                 destination = new Vector3(0,0,0);
    12.                 break;
    13.         }
    14.         foreach (GameObject unit in gameState.getActiveUnits()) {
    15.             unit.GetComponent<Unit>().move(destination);
    16.             Debug.Log("Called unit.move");
    17.         }
    18.     }
    From the movement script in the unit game object.
    Code (CSharp):
    1. void Start() {
    2.         seeker = GetComponent<Seeker>();
    3.     }
    4.  
    5.     public void setDestination (Vector3 destination) {
    6.         seeker.StartPath(transform.position, destination, OnPathComplete);
    7.         Debug.Log("Destination set.");
    8.     }
    9.  
    10.     void OnPathComplete (Path finishedPath) {
    11.         Debug.Log("Yay, we got a path back. Did it have an error? " + finishedPath.error);
    12.         path = (ABPath) finishedPath;
    13.     }
    The program only malfunctions when the ground is clicked on: when the seeker.Startpath method gets called with the mouse location as a parameter, it does return a path, but the path has zero points in its vectorPath list. An ArgumentOutOfRangeException occurs soon thereafter.

    I'm stumped! Any insight would be appreciated.
     
  2. Cannist

    Cannist

    Joined:
    Mar 31, 2020
    Posts:
    64
    Code (CSharp):
    1. destination = Input.mousePosition;
    Wouldn't you usually have to convert these screen coordinates to a world position that is actually on the ground?
     
    AidanofVT likes this.
  3. AidanofVT

    AidanofVT

    Joined:
    Nov 10, 2019
    Posts:
    104
    Hey! That was it! I'm a bit of a novice, as you can probably tell. I am still curious about why it wasn't working, though. Even though the coordinates that A* was receiving were very wrong, they were still usable X-Y coordinates, right? Why wasn't the game object able to just head off towards wherever those coordinates were in world terms?

    *edit: @Cannist Actually, now the navigation works the first time, but it throws the same error if I give the unit a second move command to another non-unit point. Interestingly, it will not throw this error if I give the new instruction before it arrives at the initial destination. Any ideas? Here's a more complete version of my movement script; the error occurs on line 12:
    Code (CSharp):
    1.     void Update() {
    2.         if (path == null) {
    3.             return;
    4.         }
    5.         if (Vector2.Distance(transform.position, path.endPoint) < roundToArrived) {
    6.             path = null;
    7.             Debug.Log("Destination reached. Path null.");
    8.             return;
    9.         }
    10.         for (int i = 0; i < 1000; i++) {
    11.             //if you are within a specified range of the next waypoint
    12.             if (Vector2.Distance(transform.position, path.vectorPath[currentWaypoint]) < changePointThreshhold) {
    13.                 //and if the number of the next waypoint would not exceeed the number of waypoints in the path
    14.                 if (currentWaypoint + 1 < path.vectorPath.Count) {
    15.                     //increment the currentWaypoint (I think there should be another break here, but it's not in the example)
    16.                     currentWaypoint++;
    17.                 }
    18.                 else {
    19.                     //end reached
    20.                     path = null;
    21.                     Debug.Log("Destination reached exactly. Path null.");
    22.                     break;
    23.                 }
    24.             }
    25.             else {
    26.                 //no incrementing needed yet
    27.                 break;
    28.             }
    29.         }
    30.         Vector3 dirNew = (path.vectorPath[currentWaypoint] - transform.position).normalized;
    31.         transform.position += dirNew * speed * Time.deltaTime;
    32.     }
     
    Last edited: May 26, 2020
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,204
    Well, the input mouse position gives the x- and y- coordinates in screen space, which means that the y-coordinate is somewhere between 0 and 1080 on a 1920x1080 monitor. For your world space, the y-axis is up, meaning that the coordinates probably were way up in the sky, which probably wouldn't be close enough to anything navigable to be of use.

    You generally want to raycast against the ground with the mouse position to find where to move to.

    For your updated question, "throws an error" isn't really much to go about with help. It essentially boils down to "here's a pile of code, there's something wrong somewhere". The type of error and line number would make it possible to help you.
     
  5. AidanofVT

    AidanofVT

    Joined:
    Nov 10, 2019
    Posts:
    104
    @Baste Sorry if I wasn't clear enough in my OP: I'm getting an ArgumentOutOfRangeException on line 12 of the above Update function. This is because it is trying to access entry 0 of a vectorPath list that is completely empty. The problem is somewhere in the path creation, which isn't part of my code but has something to do with how I'm using the A* plugin.