zeiteisen
zeiteisen

Reputation: 7168

Unity A* Pathfinding Project: Repath makes the character move to the opposite direction

please watch this short video to see the problem. As soon as there are about 23 characters they start moving in different directions. Please help me, I'm trying my best and searched for days and tried diffenrent pathfinding approaches but none worked out.

http://screencast.com/t/sUx9O0I9GQ

My setup ist a grid and the characters have a AIPath with default configuration component attached. It must be possible because I saw it in the stress test video: https://www.youtube.com/watch?v=htoen7x3LuQ

This line of code causes the trouble:

seeker.StartPath (transform.position,target.transform.position, OnPathComplete);

The complete context

public void Start () {
    InvokeRepeating ("searchPath", 1.0f, 1.0f);
    searchPath ();
}

public void searchPath() {
    GameObject target = GameObject.Find ("Target");
    seeker = GetComponent<Seeker>();
    controller = GetComponent<CharacterController>();
    //Start a new path to the targetPosition, return the result to the OnPathComplete function
    seeker.StartPath (transform.position,target.transform.position, OnPathComplete);
}

public void OnPathComplete (Path p) {
    Debug.Log ("Yay, we got a path back. Did it have an error? "+p.error);
    if (!p.error) {
        path = p;
        //Reset the waypoint counter
        currentWaypoint = 0;
    }
}

public void Update () {
    if (path == null) {
        //We have no path to move after yet
        return;
    }
    if (currentWaypoint >= path.vectorPath.Count) {
        Debug.Log ("End Of Path Reached");
        Destroy(gameObject);
        return;
    }
    //Direction to the next waypoint
    Vector3 dir = (path.vectorPath[currentWaypoint]-transform.position).normalized;
    dir *= speed * Time.deltaTime;
    controller.SimpleMove (dir);
    //Check if we are close enough to the next waypoint
    //If we are, proceed to follow the next waypoint
    if (Vector3.Distance (transform.position,path.vectorPath[currentWaypoint]) < nextWaypointDistance) {
        currentWaypoint++;
        return;
    }
}

As the title says, it's Aron Granbergs pathfinding project http://arongranberg.com/astar/

Thank you

Upvotes: 3

Views: 4403

Answers (2)

mwilczynski
mwilczynski

Reputation: 3082

Alright, I've played around with this wonderful AStar library from Aron Granbergs and I must say that using all the instructions and all the code from his tutorial it's... working just fine.

I've used the code provided by Aron from his tutorial up here, adding Destroy that you've added too. Link to tutorial: http://arongranberg.com/astar/docs/getstarted.php

Code:

using UnityEngine;
using Pathfinding;

public class PlayerScript : MonoBehaviour {

    public Vector3 targetPosition;
    private Seeker seeker;
    private CharacterController controller;
    //The calculated path
    public Path path;
    //The AI's speed per second
    public float speed = 100;
    //The max distance from the AI to a waypoint for it to continue to the next waypoint
    public float nextWaypointDistance = 3;
    //The waypoint we are currently moving towards
    private int currentWaypoint = 0;
    public void Start()
    {
        seeker = GetComponent<Seeker>();
        controller = GetComponent<CharacterController>();
        //Start a new path to the targetPosition, return the result to the OnPathComplete function
        targetPosition = GameObject.Find("Target").transform.localPosition;
        seeker.StartPath(transform.position, targetPosition, OnPathComplete);
    }
    public void OnPathComplete(Path p)
    {
        Debug.Log("Yay, we got a path back. Did it have an error? " + p.error);
        if (!p.error)
        {
            path = p;
            //Reset the waypoint counter
            currentWaypoint = 0;
        }
    }
    public void Update()
    {
        if (path == null)
        {
            //We have no path to move after yet
            return;
        }
        if (currentWaypoint >= path.vectorPath.Count)
        {
            Debug.Log("End Of Path Reached");
            Destroy(gameObject);
            return;
        }
        //Direction to the next waypoint
        Vector3 dir = (path.vectorPath[currentWaypoint] - transform.position).normalized;
        dir *= speed * Time.deltaTime;
        controller.SimpleMove(dir);
        //Check if we are close enough to the next waypoint
        //If we are, proceed to follow the next waypoint
        if (Vector3.Distance(transform.position, path.vectorPath[currentWaypoint]) < nextWaypointDistance)
        {
            currentWaypoint++;
            return;
        }
    }
}

My Player has Seeker, CharacterController and Rigidbody attached to them. I'm using Sphere primitve same as you do to simulate movement.

I've also added Duplicator for instantiating them one by one in small intervals:

PlayerDuplicator:

using UnityEngine;
using System.Collections;

public class PlayerDuplicator : MonoBehaviour
{

    public GameObject PlayerPrefab;
    public uint HowMany = 50;
    public float Interval = 0.2f;
    public Vector3 InstantiatePosition;

    // Use this for initialization
    void Start ()
    {
        StartCoroutine("DeployPlayers");
    }

    // Update is called once per frame
    void Update () {

    }

    public IEnumerator DeployPlayers()
    {
        if (PlayerPrefab == null) yield break;
        while (HowMany > 0)
        {
            var player = Instantiate(PlayerPrefab);
            player.transform.position = InstantiatePosition;
            HowMany--;
            yield return new WaitForSeconds(Interval);
        }
        yield return null;
    }
}

My outcome is here: http://screencast.com/t/auTh0uvX

Please note I did not use Simple Smooth Modifier so my spheres are hitting the obstacle gracefully on one of the curves.

I've tested it with dynamic pathfinding and your part of code:

public void Start()
{
    InvokeRepeating("searchPath", 1.0f, 1.0f);
    searchPath();
}

public void searchPath()
{
    GameObject target = GameObject.Find("Target");
    seeker = GetComponent<Seeker>();
    controller = GetComponent<CharacterController>();
    //Start a new path to the targetPosition, return the result to the OnPathComplete function
    seeker.StartPath(transform.position, target.transform.position, OnPathComplete);
}

And the outcome seem fine, but I can see your that sometimes player can lose the path for a moment. It might be indeed dependent on performance of a single thread.

My output with 100 players, Instantiate once per 0.05s:

http://www.screencast.com/users/battlefist/folders/Jing/media/9039b000-cf61-4d11-9a91-573b98e6fd91

Upvotes: 1

zeiteisen
zeiteisen

Reputation: 7168

I got a response from Aron, the author of the A* pathfinding project.

Hi

This is due to a high load on the pathfinding system. An agent might request a path when it is at some point, but since it takes some time for the path to be calculated, the agent will have moved when it gets the result back. The AIPath script tries to fix this (assuming the closestOnPathCheck field is enabled) but it cannot do it at all times. The solution is to reduce the load on the pathfinding system and the game. First, make sure you have multithreading enabled (A* Inspector -> Settings), also it is probably a good idea to turn off Show Graphs for larger graphs since drawing that is pretty slow and will reduce the fps significantly. You can also increase the pickNextWaypointDistance and the forwardLook fields on the AIPath script, that will reduce the chance of this happening.

Adding the raycast modifier will improve the performance even more. The free version only supports one thread and the pro version up to 8.

Upvotes: 2

Related Questions