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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值