A*算法
A星算法,重要是用递归,对周围的八个点或者四个点进行遍历,一直找到结束点为止
先定义节点类型
/// <summary> /// 节点类型 /// </summary> public enum NodeType { Normal, // 可以通过 Obstacle, //障碍物 }
定义格子(节点)
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 节点(格子) /// </summary> public class Node { public int x; //节点x轴位置 public int z; //节点y轴位置 public int F; //估价函数G = G+ H public int G; //表示当前节点距离起始点的位置 public int H; //表示当前节点距离结束点的位置 public Node parent; //父节点 public Transform trans; public NodeType nodeType; //该节点属性 public Node(int x, int z) { this.x = x; this.z = z; } public void SetF() { this.F = this.H + this.G; } //计算当前节点距离起始点的距离代价 public void SetG(Node parent, int value) { this.G = parent.G + value; } //计算出当前节点距离目标点的距离 public void SetH(Node target) { this.H = Mathf.Abs(target.x - this.x) + Mathf.Abs(target.z - this.z); H *= 10; } }
算法
public class AStar : MonoBehaviour { [SerializeField] private int moveSpeed = 2; [SerializeField] private Vector2Int mapSize = new Vector2Int(24, 24); //地图大小 private Transform player; //玩家 private Node[,] maps; //地图大小 private Stack<Vector3> ways = null; private Vector2Int[] dirs = //八个方向 { new Vector2Int(0,1), new Vector2Int(0,-1), new Vector2Int(1,0), new Vector2Int(-1,0), //上、下、左、右四个方向 new Vector2Int(-1,-1), new Vector2Int(1,1), new Vector2Int(-1,1), new Vector2Int(1,-1) //斜对角四个方向 }; private void Awake() { this.maps = new Node[mapSize.x, mapSize.y] ; } private void Start() { InitMaps(); InitPlayer(); int x = Random.Range(0, mapSize.x); int z = Random.Range(0, mapSize.y); maps[x, z].trans.GetComponent<Renderer>().material.color = Color.blue; //目标点 this.ways = FindWays(new Vector2(x, z)); //随机目标点 } //创建随机地图 private void InitMaps() { GameObject nodes = new GameObject("nodes"); for (int i = 0; i < maps.GetLength(0); i++) { for (int j = 0; j < maps.GetLength(1); j++) { maps[i, j] = new Node(i, j); //创建该位置节点 GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); maps[i, j].trans = go.transform; maps[i, j].trans.name = string.Format("{0},{1}", i, j); maps[i, j].trans.position = new Vector3(i, 0, j); //位置 maps[i, j].trans.localScale = Vector3.one * 0.5f; maps[i, j].trans.SetParent(nodes.transform); maps[i,j].nodeType = Random.Range(0, 10) < 8? NodeType.Normal:NodeType.Obstacle; //随机生成障碍物 switch (maps[i, j].nodeType) //可以通过的为白色,不能通过的为红色 { case NodeType.Normal: maps[i, j].trans.GetComponent<Renderer>().material.color = Color.white; break; case NodeType.Obstacle: maps[i, j].trans.GetComponent<Renderer>().material.color = Color.red; break; } } } } //初始化玩家 private void InitPlayer() { this.player = GameObject.CreatePrimitive(PrimitiveType.Capsule).transform; this.player.name = "Player"; this.player.localScale = new Vector3(0.5f,1,0.5f); int x = Random.Range(0, mapSize.x); int z = Random.Range(0, mapSize.y); maps[x, z].trans.GetComponent<Renderer>().material.color = Color.gray; this.player.position = new Vector3(x,1,z); this.player.GetComponent<Renderer>().material.color = Color.green; } //玩家位置为起始点 private Node GetFirstNode() { int x = (int)this.player.position.x; int z = (int)this.player.position.z; return this.maps[x,z]; } //根据位置获取目标节点 private Node GetTargetNode(Vector2 targetPos) { int x = (int)targetPos.x; int z = (int)targetPos.y; return maps[x, z]; //if (isOk(x, z)) //{ // return maps[x, z]; //} //else //{ // return null; //} } //寻找目标点 List<Node> closeList = new List<Node>(); //必须要寻找的节点 private Node FindTarget(Vector2 targetPos) { Node firstNode = GetFirstNode(); Debug.Log("起始点:" + firstNode.trans.name); Node targetNode = GetTargetNode(targetPos); if (targetNode == null) { Debug.Log("目标点不存在或者不合法"); return null; } Debug.Log("目标点:" + targetNode.trans.name); List<Node> openList = new List<Node>(); //需要计算的节点 openList.Add(firstNode); closeList.Add(firstNode); while (openList.Count > 0) { Node node = openList[0]; for (int i = 0; i < dirs.Length; i++) { int x = node.x + dirs[i].x; int z = node.z + dirs[i].y; int value = i < 4 ? 10: 14; if (isOk(x, z, node, value)) { //满足条件的节点放入OpenList maps[x, z].parent = node; //设置父元素 maps[x, z].SetG(node, value); maps[x, z].SetH(targetNode); maps[x, z].SetF(); openList.Sort(Compare); if (maps[x, z] == targetNode) { Debug.Log(targetNode.x + "," + targetNode.z); return maps[x, z]; //找到目标点 } closeList.Add(maps[x,z]); openList.Add(maps[x,z]); } } openList.Remove(node); } return null; } //排序 public int Compare(Node left, Node right) { if (left.F > right.F) { return 1; } if (left.F < right.F) { return -1; } return 0; } //寻路 private Stack<Vector3> FindWays(Vector2 targetPos) { Node targetNode = FindTarget(targetPos); if (targetNode != null) { Debug.Log("找到的Target:" + targetNode.trans.name); } Stack<Vector3> ways = new Stack<Vector3>(); //从目标点往起始点寻找,栈最上面为起始点,然后以此弹出为路径 while (targetNode != null) { Vector3 pos = new Vector3(targetNode.x, 0, targetNode.z); ways.Push(pos); targetNode = targetNode.parent; } return ways; } //是否满足条件 private bool isOk(int x, int z, Node parent, int value) { if (x < maps.GetLength(0) && x >=0 && z < maps.GetLength(1) && z >= 0) { Node node = maps[x, z]; if (node.nodeType == NodeType.Obstacle ) { return false; //障碍物,已经寻找过的也返回false } if (closeList.Contains(maps[x, z])) //如果已经访问了,也返回假 { //检测更新G值 if (maps[x, z].G > parent.G + value) { Debug.Log(maps[x,z].trans.name + "+++++" + parent.trans.name + "G:" + parent.G + "===" + value); maps[x, z].G = parent.G + value; maps[x, z].parent = parent; } return false; } else { return true; } } else { return false; //超出地图范围 } } private void Update() { if (ways != null && ways.Count > 0) { Vector3 lastPos = ways.Peek(); Vector3 targetPos = new Vector3(lastPos.x, player.position.y, lastPos.z); if (Vector3.Distance(player.position, targetPos) > 0.02f) { Vector3 dirNormal = Vector3.Normalize(targetPos - player.position); player.Translate(dirNormal * Time.deltaTime * moveSpeed); } else { ways.Pop(); } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理