在点图上为先前路径添加惩罚以防止掉头? A *寻路项目

时间:2014-03-05 19:22:54

标签: graph unity3d path-finding a-star

我正在使用Aron Granberg的A *寻路项目。所以我在这张图片中设置了一个点图:

我让每辆车在点图上选择一个随机节点并遵循它的路径。

现在,在路上行驶的汽车倾向于转弯到达下一个目的地。例如,假设原始路径是从A点到B点。一旦汽车到达B点,它随机选择前往C点。

有什么方法可以强制它总是采用黄色路径而不是紫色路径来防止掉头?我正在考虑为前一条路径设置处罚的方法,但是处罚只能适用于单一的代理人,因为我不希望罚款适用于其他车辆在路上。有可行的方法吗?我在下面列出了我的寻路代码。

using UnityEngine;
using System.Collections;
using System.Linq;
//Note this line, if it is left out, the script won't know that the class 'Path' exists and it will throw compiler errors
//This line should always be present at the top of scripts which use %Pathfinding
using Pathfinding;

public class newPathfind : MonoBehaviour {
    //The point to move to
    private Vector3 targetPosition;

    private bool pathComplete;

    public bool ManualList = false;
    //public int members = 0;
    //private int x = 0;
    public GameObject target1;
    public GameObject target2;
    public GameObject target3;
    public GameObject target4;
    public GameObject target5;

    private GameObject[] Waypoints;
    private GameObject[] oneway;
    private GameObject[] twoway;
    public static int randomPoint;

    private Seeker seeker;
    private CharacterController controller;

    //The calculated path
    public Path path;

    //The AI's speed per second
    public float speed = 500;

    //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>();



        Vector3 randomLoc = Vector3.zero;

        if (ManualList) {
            Waypoints = new GameObject[5];
            Waypoints[0] = target1;
            Waypoints[1] = target2;
            Waypoints[2] = target3;
            Waypoints[3] = target4;
            Waypoints[4] = target5;
        } else {
            //Waypoints = GameObject.FindGameObjectsWithTag("network");
            twoway = GameObject.FindGameObjectsWithTag ("network");
            oneway = GameObject.FindGameObjectsWithTag ("oneway");
            Waypoints = oneway.Concat (twoway).ToArray ();
        }

        do {
            randomPoint = Random.Range (0, Waypoints.Length-1);
            randomLoc = Waypoints[randomPoint].transform.position;
            targetPosition = new Vector3 (randomLoc.x, gameObject.transform.position.y, randomLoc.z);
        } while ((Vector3.Distance(gameObject.transform.position, targetPosition) < 50f));

        //Start a new path to the targetPosition, return the result to the OnPathComplete function
        seeker.StartPath (transform.position,targetPosition, OnPathComplete);
    }

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

        if (path == null) {
            return;
        }

        if (currentWaypoint >= path.vectorPath.Count && pathComplete == true) {
            Debug.Log ("End Of Path Reached");
            Start();
            pathComplete = false;
            return;
        }

        //Direction to the next waypoint
        Vector3 dir = Vector3.zero;
        if (currentWaypoint >= 0 && currentWaypoint < path.vectorPath.Count) {
            dir = (path.vectorPath [currentWaypoint] - transform.position).normalized;
        }
        if (dir != Vector3.zero) {
            transform.rotation = Quaternion.LookRotation (dir);
        }
        dir *= speed * Time.fixedDeltaTime;
        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;
        }
    }
    public void OnDisable () {
        seeker.pathCallback -= OnPathComplete;
    } 
}

3 个答案:

答案 0 :(得分:0)

我无法使用Aron Granberg的A *寻路项目找到如何做到这一点,但基本上你需要将上次访问节点的成本改为其正常成本的3-5倍(可能需要试验) )再次调用seeker.StartPath之前。

我认为探路者可以通过某种方式询问每个节点的成本。如果节点与单元访问的最后一个节点相同,则返回其实际成本的倍数。当然,您需要知道它正在寻找哪个单位。

我能找到的最近的东西(对图书馆一无所知)是GraphUpdates,你可以在各种节点上应用惩罚:

GraphUpdateObject guo = new GraphUpdateObject(myBounds);
guo.addPenalty = 10000; //Here goes the penalty to apply, you need quite large values usually
AstarPath.active.UpdateGraphs (guo);

在调用特定单位的导引头之前,不确定如何将其与除更新图表之外的其他单位联系起来,并确保在完成之前没有其他人调用导引头(非常低效)。

答案 1 :(得分:0)

难题......你可以做的一件事(对于已经行驶的汽车)是评估汽车路径上的直线到下一个十字路口。这将是驾驶员决定重新计算其路径的下一个合乎逻辑的时间。这样做会告诉汽车继续使用导引头,直到它找到路径的起​​始节点(在这种情况下,它会大大减少你的掉头行为)恰好在下一个十字路口,使你的假设更不可能更接近模仿驾驶行为。

同样在繁忙的道路上,您可能需要考虑使用名为“替代路径”的过滤器...如果将其添加到现有的汽车预制件中,则可以为使用相同路径的其他单元创建惩罚。如果你把它设置为......说100,除非它是唯一的现实路径,在10辆车采用相同的路径后,你可能会让汽车采用其他路线

只是我的两分钱

我编辑了两美分,为道路增加了重量,除非它是整条道路(即泥土与路面)不太可行。除非我错过了文档中的内容(如果我因为想要使用它而告诉我),您无法获得给定节点/航点的权重。但是,您可以选择具有不同惩罚的不同路径。 (IE你不能做path.vectorPath [currentWaypoint] .weight,但你可以做path.GetTagPenalty并选择一个备用路径)

答案 2 :(得分:0)

“高级”部分中的角度惩罚可能对此有所帮助。