自学内容网 自学内容网

Unity中实现A*寻路算法参考

A*路径获取代码:

using System.Collections.Generic;
using UnityEngine;

public class AStarNode
{
public int id { get; set; }
public Vector3 position;
public List<int> listNeighbor { get; set; }

public AStarNode(int id, Vector3 position)
{
this.id = id;
this.position = position;
listNeighbor = new List<int>();
}
}

public class AStarFindPath
{
private static Dictionary<int, float> gScore;
private static Dictionary<int, float> fScore;

public static List<AStarNode> GetPath(Dictionary<int, AStarNode> nodes, int startId, int goalId)
{
var openSet = new SortedSet<(int, float)>(Comparer<(int, float)>.Create((a, b) =>
{
int compareResult = a.Item2.CompareTo(b.Item2);
return compareResult == 0 ? a.Item1.CompareTo(b.Item1) : compareResult;
}));

var cameFrom = new Dictionary<int, int>();

gScore = new Dictionary<int, float>();
fScore = new Dictionary<int, float>();

foreach (var node in nodes.Values)
{
gScore[node.id] = float.MaxValue;
fScore[node.id] = float.MaxValue;
}

gScore[startId] = 0;
fScore[startId] = (nodes[startId].position -nodes[goalId].position).magnitude;

openSet.Add((startId, fScore[startId]));

while (openSet.Count > 0)
{
var currentItem = openSet.Min;
int current = currentItem.Item1;
openSet.Remove(currentItem);

if (current == goalId)
{
return ReconstructPath(cameFrom, nodes, current);
}

foreach (int neighborId in nodes[current].listNeighbor)
{
float tentativeGScore = gScore[current] + (nodes[current].position - nodes[neighborId].position).magnitude;

if (tentativeGScore < gScore[neighborId])
{
cameFrom[neighborId] = current;
gScore[neighborId] = tentativeGScore;
fScore[neighborId] = gScore[neighborId] + (nodes[neighborId].position - nodes[goalId].position).magnitude;

var neighborItem = (neighborId, fScore[neighborId]);
if (!openSet.Contains(neighborItem))
{
openSet.Add(neighborItem);
}
else
{
openSet.Remove(neighborItem);
openSet.Add(neighborItem);
}
}
}
}

return null; // 找不到路径
}

private static List<AStarNode> ReconstructPath(Dictionary<int, int> cameFrom, Dictionary<int, AStarNode> nodes, int current)
{
var totalPath = new List<AStarNode> { nodes[current] };

while (cameFrom.ContainsKey(current))
{
current = cameFrom[current];
totalPath.Insert(0, nodes[current]);
}

return totalPath;
}
}

在Unity中的测试代码:

using System.Collections.Generic;
using UnityEngine;

public class TestAStar : MonoBehaviour
{
[SerializeField]
Material material;

List<GameObject> listNodeObj = new();

void Start()
{
CreateAStarPath();
}

int nodeCount = 200;
void CreateAStarPath()
{
Clear();

for (int i = 0; i < nodeCount; i++)
{
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
obj.transform.SetParent(transform);
obj.transform.localPosition = new Vector3(Random.Range(-100, 100), Random.Range(-10, 10), Random.Range(-100, 100));
obj.name = i.ToString("D3");
listNodeObj.Add(obj);
}

Dictionary<int, AStarNode> dicAStarNode = new();

for (int i = 0; i < nodeCount; i++)
{
List<int> listNeighbor = new();
Vector3 pos = listNodeObj[i].transform.position;
for (int j = 0; j < nodeCount; j++)
{
if (i == j) continue;

Vector3 posB = listNodeObj[j].transform.position;
if ((pos - posB).sqrMagnitude < 900)
{
listNeighbor.Add(j);
}
}

if (listNeighbor.Count > 0)
{
AStarNode aStarNode = new(i, pos)
{
listNeighbor = listNeighbor
};
dicAStarNode.Add(i, aStarNode);
}
}

List<AStarNode> path = AStarFindPath.GetPath(dicAStarNode, 0, nodeCount-1);

if (path != null && path.Count > 1)
{
GameObject pathObj = new("Path");
pathObj.transform.SetParent(transform);
LineRenderer lineRenderer = pathObj.AddComponent<LineRenderer>();
Vector3[] points = new Vector3[path.Count];
for (int i = 0; i < path.Count; i++)
{
points[i] = path[i].position;
}
lineRenderer.positionCount = points.Length;
lineRenderer.SetPositions(points);
lineRenderer.material = material;

listNodeObj.Add(pathObj);
}
}

void Clear()
{
for (int i = 0; i < listNodeObj.Count; i++)
{
Destroy(listNodeObj[i]);
}
listNodeObj.Clear();
}
}


原文地址:https://blog.csdn.net/ttod/article/details/144116894

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!