-1
\$\begingroup\$

As the title suggests I have been following the wonderful series of tutorials dealing with pathfinding made by Sebastian Lague.

My problem is that the code is meant to be working immediately after launching the scene. It works fine and all, but I simply cannot seem to make it run on a condition, be it a mouse click or any other sort of trigger. Did somebody manage to do it? If so can you please explain please?

In the specific, the problems start to arise going from the 4th to the 5th video, in which mutliple units are taken into account and therefore a new script handling the multiple requests to find paths is added.

The main method in the pathfinding script is this (let's call it pathfinding):

public void StartFindPath(Vector3 startPos, Vector3 targetPos) {
    StartCoroutine(FindPath(startPos, targetPos));
}

And the called coroutine is something like:

IEnumerator FindPath(Vector3 startPosition, Vector3 targetPosition) {
    Stopwatch sw = new Stopwatch();
    sw.Start();
    Vector3[] wayPoints = new Vector3[0];
    bool pathSuccess = false;

    Node1 startNode = grid.NodeFromWorldPoint(startPosition);
    Node1 targetNode = grid.NodeFromWorldPoint(targetPosition);

    if (startNode.walkable && targetNode.walkable) {
        //<Update open & closed lists>
        while (openSet.Count > 0) {
            Node1 currentNode = openSet.RemoveFirst();
            closedSet.Add(currentNode);

            if (currentNode == targetNode) {
                sw.Stop();
                pathSuccess = true;
                RetracePath(startNode, targetNode);
                break;
            }

            foreach (Node1 neighbor in grid.GetNeighbors(currentNode)) {
                // Retrieve f cost and find a path
            }
        }
    }
    yield return null;
    if (pathSuccess) {
        wayPoints = RetracePath(startNode, targetNode);
    }

    requestManager.FinishedProcessingPath(wayPoints,pathSuccess);
}

The request manager script (requestManager) instead is this:

public class PathRequestManager : MonoBehaviour {
    Queue<PathRequest> pathRequestQueue = new Queue<PathRequest>();
    PathRequest currentPathRequest;

    static PathRequestManager instance;
    PathFinding pathFinding;

    bool isProcessingPath;

    private void Awake() {
        instance = this;
        pathFinding = GetComponent<PathFinding>();
    }

    public static void RequestPath(Vector3 pathStart, Vector3 pathEnd, Action<Vector3[], bool> callback) {
        PathRequest newRequest = new PathRequest(pathStart, pathEnd, callback);
        instance.pathRequestQueue.Enqueue(newRequest);
        instance.TryProcessNext();
    }

    void TryProcessNext() {
        if (!isProcessingPath && pathRequestQueue.Count > 0) {
            currentPathRequest = pathRequestQueue.Dequeue();
            isProcessingPath = true;
            pathFinding.StartFindPath(currentPathRequest.pathStart, currentPathRequest.pathEnd);
        }
    }

    public void FinishedProcessingPath(Vector3[] path, bool success) {
        currentPathRequest.callback(path, success);
        isProcessingPath = false;
        TryProcessNext();
    }

    struct PathRequest {
        public Vector3 pathStart;
        public Vector3 pathEnd;
        public Action<Vector3[], bool> callback;

        public PathRequest(Vector3 _start, Vector3 _end, Action<Vector3[], bool> _callback) {
            pathStart = _start;
            pathEnd = _end;
            callback = _callback;
        }
    }
}

Finally, each unit object is provided with a "unit" script in which there is this corouting used to follow the path retrieved from the pathfinding script:

IEnumerator FollowPath() {
    Vector3 currentWayPoint = path[0];

    while (true) {
        if (transform.position == currentWayPoint) {
            targetIndex++;
            if (targetIndex >= path.Length) {
                yield break;
            }
            currentWayPoint = path[targetIndex];
        }

        transform.position = Vector2.MoveTowards(transform.position, currentWayPoint, speed * Time.deltaTime);
        yield return null;
    }
}

I tried at first to wrap the the StartFindPath() in pathfinding in an if statement made true upon pressing a button, but it did not work, so i tried to do the same only with the StartCoroutine line, but I ended up with the same result. I thought about doing it for the FollowPath method in the unit script, but it is called in this method:

public void OnPathFound(Vector3[] newPath, bool pathSuccessful) {
    if (pathSuccessful) {
        path = newPath;
        StopCoroutine(FollowPath());
        StartCoroutine(FollowPath());
    }
}

And I am not sure if it is the most suitable way. I tried to limit as much as possible the amount of code in the question, but if you need more I will add the rest of the scripts (FYI there are also a script in which the nodes features are defined, one to create the grid and one to define the heap data structure).

\$\endgroup\$
  • 1
    \$\begingroup\$ Can you show us a minimal sample of how you're running your A* pathfinding search currently (at the start of the scene), and how you've tried to run it on a condition instead? \$\endgroup\$ – DMGregory May 6 at 12:09
  • \$\begingroup\$ Sorry for the delay in the reply, I will edit the question! \$\endgroup\$ – FSic May 8 at 14:31
1
\$\begingroup\$

It looks like your path processing is kicked off by RequestPath. The calls to that are what you need to wrap in the if.

So a patrolling unit could have

if(transform.position == target.position){
    target = newtTargetPosition();
    RequestPath(transform.position, target, OnPathFound);
}

answer before edit:
Where ever you call the do_Astar function you wrap it in an if that checks whether you need to run A*.

if(need_repath){ do_Astar(); need_repath = false; }
\$\endgroup\$
  • \$\begingroup\$ Thanks for the suggestion, but I have tried it. I think that the main problem is that the "do _Astar" is called within another method. \$\endgroup\$ – FSic May 8 at 14:55
0
\$\begingroup\$

For anybody using the scripts from the tutorials I mentioned, I have found the solution, it's just like as ratchet freak said, only it was another function.

For those familiar with the scripts, the Unit script, is the one attached to each unit in your scene, in its update method you can find the RequestPath, called from the PathRequestManager script. RequestPath will then start the pathfinding process and from the Pathfinding script the shortest path will be used in the OnPathFound method back in the Unit script to actually make the unit follow the path. Therefore in order to start the whole process upon a condition, you have to put such condition the first time the RequestPath method is called, like this:

private void Update()//Change from Start to Update so that it looks for path during game, not at the beginning
{
    /*Put the condition here if you want to make it look for a path only when you want it*/
    if (Input.GetKeyDown(KeyCode.Space)) {
        PathRequestManager.RequestPath(transform.position, target.position, OnPathFound);
    }
}

Hope it can be useful for somebody else, cheers!

\$\endgroup\$

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.