代码之家  ›  专栏  ›  技术社区  ›  WiseDev

动态寻路A*Unity3D C#

  •  1
  • WiseDev  · 技术社区  · 9 年前

    我正尝试在Unity3D中使用A*寻路,如果目标保持静止,它就会起作用。然而,如果目标移动,单位仍将遵循相同的路径。找到下面每个单元的代码(附在导引头对象上):

    using UnityEngine;
    using System.Collections;
    
    public class Unit : MonoBehaviour {
    
        public Transform target;
        float speed = 20;
        Vector3[] path;
        int targetIndex;
    
    void Start() {
        PathRequestManager.RequestPath(transform.position,target.position, OnPathFound);
    }
    
    public void OnPathFound(Vector3[] newPath, bool pathSuccessful) {
        if (pathSuccessful) {
            path = newPath;
            StopCoroutine("FollowPath");
            StartCoroutine("FollowPath");
        }
    }
    
    IEnumerator FollowPath() {
        Vector3 currentWaypoint = path[0];
    
        while (true) {
            if (transform.position == currentWaypoint) {
                targetIndex ++;
                if (targetIndex >= path.Length) {
                    yield break;
                }
                currentWaypoint = path[targetIndex];
            }
    
    
            transform.position = Vector3.MoveTowards(transform.position,currentWaypoint,speed * Time.deltaTime);
            yield return null;
    
        }
    }
    
    public void OnDrawGizmos() {
        if (path != null) {
            for (int i = targetIndex; i < path.Length; i ++) {
                Gizmos.color = Color.black;
                Gizmos.DrawCube(path[i], Vector3.one);
    
                if (i == targetIndex) {
                    Gizmos.DrawLine(transform.position, path[i]);
                }
                else {
                    Gizmos.DrawLine(path[i-1],path[i]);
                }
            }
        }
    }
    

    }

    现在,如果我尝试通过将void Start()更改为void Update()来使用它进行动态路径查找(目标移动和路径更新),这将不起作用。该响应将导致奇怪的单元行为,一直来回移动或未完成路径等。 现在我不知道这件事的确切原因,可能是因为验尸程序? 无论如何,我如何才能更改代码,从而获得正确的动态路径查找结果?

    提前谢谢!

    另外,所有剩余的源代码都可以在这里找到: http://bit.ly/pathfindingSource

    2 回复  |  直到 9 年前
        1
  •  1
  •   Jerry Switalski    9 年前

    只要该逻辑的设计不是最佳的,那么当到达下一个航路点时,尝试重新计算路径:

    IEnumerator FollowPath() {
        Vector3 currentWaypoint = path[0];
    
        while (true) {
            if (transform.position == currentWaypoint) {
    
               PathRequestManager.RequestPath(transform.position,target.position, OnPathFound);
    
    targetIndex = 0;
                targetIndex ++;
                if (targetIndex >= path.Length) {
                    yield break;
                }
                currentWaypoint = path[targetIndex];
            }
    
    
            transform.position = Vector3.MoveTowards(transform.position,currentWaypoint,speed * Time.deltaTime);
            yield return null;
    
        }
    

    如果你想进行动态寻路,你需要在每次到达下一个航路点时重新计算路径,或者有其他逻辑,比如当一些对象移动时触发一个事件,你需要重新计算路径。

        2
  •  0
  •   WiseDev    9 年前

    我已经“解决”了这个问题,现在有了一个足够好的解决方案。

    首先,我通过在每个航路点请求一条新路径,使寻路变得动态。其次,即使在到达目标后,路径查找仍在继续,通过一些逻辑,检查每一帧单元是否足够远,以重复协同程序。如果是,则停止旧的协同程序并启动新的协同程序。

    下面是代码:

    using UnityEngine;
    using System.Collections;
    
    public class Unit : MonoBehaviour {
    
    public Transform target;
    float speed = 20;
    Vector3[] path;
    int targetIndex;
    
    bool  newRequestReady;
    
    void Start() {
        PathRequestManager.RequestPath(transform.position,target.position, OnPathFound);
    
        newRequestReady = false;
    }
    
    void Update(){
        float distance = Vector3.Distance (transform.position, target.position);
        Debug.Log(distance);
    
        if(distance < 5){
            StopCoroutine("FollowPath");
            newRequestReady = true;
        }
        else if(distance >=10 && newRequestReady){
            PathRequestManager.RequestPath(transform.position,target.position, OnPathFound);
            StopCoroutine("FollowPath");
            newRequestReady = false;
    
        }
    }
    
    public void OnPathFound(Vector3[] newPath, bool pathSuccessful) {
        if (pathSuccessful) {
            path = newPath;
            StopCoroutine("FollowPath");
            StartCoroutine("FollowPath");
        }
    }
    
    IEnumerator FollowPath() {
        Vector3 currentWaypoint = path[0];
    
        while (true) {
    
            if (transform.position == currentWaypoint) {
                PathRequestManager.RequestPath(transform.position,target.position,OnPathFound);
                targetIndex=0;
    
                targetIndex ++;
                //Debug.Log(currentWaypoint);
    
                if (targetIndex >= path.Length) {
                    targetIndex =0;
                    path = new Vector3[0];
                //yield break;
                }
                currentWaypoint = path[targetIndex];
            }
                transform.position = Vector3.MoveTowards(transform.position,currentWaypoint,speed * Time.deltaTime);
    
            yield return null;
        }
    }
    
    
    }