动态寻路 A* Unity3D C#
Dynamic Pathfinding A* Unity3D C#
我正在尝试在 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() 来将其用于动态寻路(目标移动和路径更新),这将不起作用。响应将导致奇怪的单位行为,一直来回移动或未完成路径等。
现在我不知道造成这种情况的确切原因,可能是因为协程?
无论如何,我如何更改代码才能得到正确的动态寻路结果?
提前致谢!
P.S。所有剩余的源代码都可以在这里找到: http://bit.ly/pathfindingSource
只要这个逻辑的设计不是最优的,尝试在到达下一个航路点时重新计算路径:
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;
}
如果你想要动态寻路,你需要在每次到达下一个路点时重新计算路径,或者有其他逻辑,比如当一些对象移动时触发一个事件 - 在处理程序中你重新计算路径。
我已经 "fixed" 解决了这个问题,现在有一个足够好的解决方案。
首先,我通过在每个航路点请求一条新路径来使寻路动态化。其次,寻路甚至在到达目标后继续进行,通过某种逻辑检查每一帧,这些单元是否再次足够远以重复协程。如果是,则停止旧的协程并启动新的协程。
代码如下:
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;
}
}
}
我正在尝试在 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() 来将其用于动态寻路(目标移动和路径更新),这将不起作用。响应将导致奇怪的单位行为,一直来回移动或未完成路径等。 现在我不知道造成这种情况的确切原因,可能是因为协程? 无论如何,我如何更改代码才能得到正确的动态寻路结果?
提前致谢!
P.S。所有剩余的源代码都可以在这里找到: http://bit.ly/pathfindingSource
只要这个逻辑的设计不是最优的,尝试在到达下一个航路点时重新计算路径:
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;
}
如果你想要动态寻路,你需要在每次到达下一个路点时重新计算路径,或者有其他逻辑,比如当一些对象移动时触发一个事件 - 在处理程序中你重新计算路径。
我已经 "fixed" 解决了这个问题,现在有一个足够好的解决方案。
首先,我通过在每个航路点请求一条新路径来使寻路动态化。其次,寻路甚至在到达目标后继续进行,通过某种逻辑检查每一帧,这些单元是否再次足够远以重复协程。如果是,则停止旧的协程并启动新的协程。
代码如下:
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;
}
}
}