当前位置: 首页 > article >正文

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


http://www.kler.cn/a/419210.html

相关文章:

  • 【JavaEE】JavaEE、web 开发、框架(Spring) 、Maven
  • android shader gl_Position是几个分量
  • springboot366高校物品捐赠管理系统(论文+源码)_kaic
  • 联合汽车电子嵌入式面试题及参考答案
  • 一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单
  • Vue中实现函数限流:节流和防抖
  • Scala 的知识点
  • Linux中pcap_loop()函数
  • 算法的复杂度
  • LeetCode:19.删除链表倒数第N个节点
  • 解决jupyter notebook 新建或打开.ipynb 报500 : Internal Server Error(涉及jinja2兼容性问题)
  • 蓝桥-希尔排序模板题
  • 【Java基础面试题004】封装、继承、重载、多态、接口和抽象类是什么?
  • 《JavaEat:探索 Java 在美食世界的奇妙之旅》
  • 无星的微前端之旅(四)——qiankun线上服务代理到本地
  • 后端-一对一的数据封装的两种写法对比
  • Android 图形系统之六:BufferQueue
  • 信息网络安全考试gjdw
  • 网络安全运维——高级 题库一 50题
  • vue3 + vite + antdv 项目中自定义图标
  • 华为OD机试真题---幼儿园篮球游戏
  • 【解决安全扫描漏洞】---- 检测到目标站点存在 JavaScript 框架库漏洞
  • 【Vue3】【Naive UI】<NDropdown>标签
  • 【机器学习】机器学习学习笔记 - 监督学习 - 多项式回归决策树回归 - 03
  • 【拥抱AI】如何查看Milvus的使用情况?
  • redis实战:集群的session问题