【问题标题】:Add penalty to previous path on point graph to prevent u-turns? A* Pathfinding Project对点图上的先前路径添加惩罚以防止掉头? A* 寻路项目
【发布时间】:2014-03-05 19:22:54
【问题描述】:

我正在使用 Aron Granberg 的 A* Pathfinding Project。所以我在这张图中设置了一个点图:

我让每辆车在点图上选择一个随机节点并沿着一条路径到达它。

目前,在路上行驶的汽车倾向于掉头到达下一个目的地。例如,假设原来的路径是从 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;
    } 
}

【问题讨论】:

    标签: graph unity3d path-finding a-star


    【解决方案1】:

    我无法使用 Aron Granberg 的 A* Pathfinding Project 找到如何做到这一点,但基本上你需要将最后访问节点的成本更改为正常成本的 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);
    

    除了在调用特定单元的搜索器之前更新图表并确保在完成之前没有其他人调用搜索器(非常低效)之外,您不确定如何将此与单元联系起来。

    【讨论】:

      【解决方案2】:

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

      此外,在繁忙的道路上,您可能需要考虑使用称为替代路径的过滤器...如果您将其添加到现有的汽车预制件中,您可能会因为太多其他单元采用相同的路径而受到惩罚。如果您将其设置为...比如说 100,除非它是唯一现实的路径,否则在 10 辆汽车走同一条路后,您可能会让汽车走其他路线

      只要我的两分钱

      我编辑了两美分,增加了道路的权重,除非它是整个道路(即泥土与人行道)不太可行。除非我错过了文档中的某些内容(让我知道是否因为我想使用它而错过了),否则您无法获得给定节点/航点的权重。但是,您可以在具有不同惩罚的不同路径之间进行选择。 (IE你不能做path.vectorPath[currentWaypoint].weight,但你可以做path.GetTagPenalty并选择替代路径)

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 2016-06-14
          • 2014-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-15
          • 2019-02-09
          • 2017-06-15
          • 1970-01-01
          相关资源
          最近更新 更多