传奇广告查询第一站 同步54.com

UnityA星寻路-3个脚本超简易实现
原创 于2026-01-05 18:07:00发布
9 阅读
0
0

实现效果
未运行默认状态

[a*寻路scene场景绘制效果]a*寻路scene场景绘制效果

脚本绑定:
![[Pasted image 20231212144346.png]]

源码:
1 .FindPath

using UnityEngine; using System.Collections; using System.Collections.Generic; public class FindPath : MonoBehaviour { public Transform player, EndPoint; Grid grid; void Start() { grid = GetComponent(); } void Update() { FindingPath(player.position, EndPoint.position); Control(); } ///  /// 控制移动方法(测试用) ///  public virtual void Control() { if (Input.GetKey(KeyCode.W)) { if (grid.path.Count > 0) { player.position = grid.path[0].WorldPos; } } } ///  /// 获取两点之间的距离 ///  ///  ///  void FindingPath(Vector3 StartPos, Vector3 EndPos) { Node startNode = grid.GetFromPostion(StartPos); Node EndNode = grid.GetFromPostion(EndPos); List openSet = new List(); HashSet closeSet = new HashSet(); openSet.Add(startNode); //当开启列表中还有元素的情况下不断的查找最优点 while (openSet.Count > 0) { Node currentNode = openSet[0]; for (int i = 0; i < openSet.Count; i++) { //如果openSet[i]的费用低于currentNode或者......... if (openSet[i].FCost < currentNode.FCost || openSet[i].FCost == currentNode.FCost && openSet[i].hCost < currentNode.hCost) { currentNode = openSet[i]; } } //如果该节点是最优点,从开始列表中移除 openSet.Remove(currentNode); //添加到关闭列表 closeSet.Add(currentNode); if (currentNode == EndNode) { GeneratePath(startNode, EndNode); return; } foreach (var node in grid.GetNeibourhood(currentNode)) { if (!node.CanWalk || closeSet.Contains(node)) continue; //计算相邻格子的消费 int newCost = currentNode.gCost + GetDistanceNodes(currentNode, node); if (newCost < node.gCost || !openSet.Contains(node)) { node.gCost = newCost; node.hCost = GetDistanceNodes(node, EndNode); node.parent = currentNode; if (!openSet.Contains(node)) { openSet.Add(node); } } } } } //递归Node的父节点 得到最终的寻路路径 private void GeneratePath(Node StartNode, Node EndNode) { List path = new List(); Node temp = EndNode; //当目标节点不是开始节点的话循环 while (temp != StartNode) { path.Add(temp); temp = temp.parent; } path.Reverse(); grid.path = path; } int GetDistanceNodes(Node a, Node b) { int cntX = Mathf.Abs(a.gridX - b.gridX); int cntY = Mathf.Abs(a.gridY - b.gridY); if (cntX > cntY) { return 14 * cntY + 10 * (cntX - cntY); } else { return 14 * cntX + 10 * (cntY - cntX); } } } 

2.Grid

using UnityEngine; using System.Collections; using System.Collections.Generic; public class Grid : MonoBehaviour { private Node[,] grid; ///  /// 网格大小 ///  public Vector2 gridSize; ///  /// 每个网格的半径 ///  public float nodeRadius; ///  /// 每个网格的直径 ///  public float nodeDiameter; ///  /// 获得不可行走的层 ///  public LayerMask WhatLayer; ///  /// 网格的长度 ///  public int gridCntX; public int gridCntY; public Transform player; public List path = new List(); void Start() { nodeDiameter = nodeRadius * 2; gridCntX = Mathf.RoundToInt(gridSize.x / nodeDiameter); gridCntY = Mathf.RoundToInt(gridSize.y / nodeDiameter); grid = new Node[gridCntX, gridCntY]; CreatGrid(); } ///  /// 初始化网格数据 ///  private void CreatGrid() { //获取初始位置 Vector3 startPoint = transform.position - gridSize.x / 2 * Vector3.right - gridSize.y / 2 * Vector3.forward; for (int i = 0; i < gridCntX; i++) { for (int j = 0; j < gridCntY; j++) { Vector3 worldPoint = startPoint + Vector3.right * (i * nodeDiameter + nodeRadius) + Vector3.forward * (j * nodeDiameter + nodeRadius); bool walkable = SelectUnWalkable(worldPoint); grid[i, j] = new Node(walkable, worldPoint, i, j); } } } ///  /// 获取格子相对应该的节点位置 ///  /// 格子的V3位置 ///  public Node GetFromPostion(Vector3 postion) { //获取该位置在X,Y轴上的百分比 float percentX = (postion.x + gridSize.x / 2) / gridSize.x; float percentY = (postion.z + gridSize.y / 2) / gridSize.y; percentX = Mathf.Clamp01(percentX); percentY = Mathf.Clamp01(percentY); int x = Mathf.RoundToInt((gridCntX - 1) * percentX); int y = Mathf.RoundToInt((gridCntY - 1) * percentY); return grid[x, y]; } //绘制辅助显示线框 void OnDrawGizmos() { //绘制一个线框Cuble 参数1:位置 参数2:线框大小 Gizmos.DrawWireCube(transform.position, new Vector3(gridSize.x, 1, gridSize.y)); if (grid == null) return; //绘制基础地图点 foreach (var node in grid) { Gizmos.color = node.CanWalk ? Color.white : Color.red; Gizmos.DrawCube(node.WorldPos, Vector3.one * (nodeDiameter - 0.05f)); } Node playerNode = GetFromPostion(player.position); //绘制寻路点 foreach (var node in path) { Gizmos.color = Color.black; Gizmos.DrawCube(node.WorldPos, Vector3.one * (nodeDiameter - 0.05f)); } //绘制起始点 if (playerNode != null && playerNode.CanWalk) { Gizmos.color = Color.cyan; Gizmos.DrawCube(playerNode.WorldPos, Vector3.one * (nodeDiameter - 0.05f)); } } ///  /// 获取选定节点的相邻节点(此处可优化,建议处理成在初始化的时候就记录好相邻格子的数据列表) ///  ///  ///  public List GetNeibourhood(Node node) { List neibourhood = new List(); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) { continue; } int tempX = node.gridX + i; int tempY = node.gridY + j; if (tempX < gridCntX && tempX > 0 && tempY > 0 && tempY < gridCntY) { neibourhood.Add(grid[tempX, tempY]); } } } return neibourhood; } ///  /// 设置选择遮挡路径的方式 ///  ///  ///  public virtual bool SelectUnWalkable(Vector3 worldPoint) { bool walkable = !Physics.CheckSphere(worldPoint, nodeRadius, WhatLayer); return walkable; } } 

3.Node

using UnityEngine; using System.Collections; public class Node { //是否可以行走 public bool CanWalk; //世界坐标 public Vector3 WorldPos; //相对坐标 X,Y public int gridX, gridY; //从跟节点到此节点的总费用 public int gCost; //从父节点走到此节点花费的费用 public int hCost; //父节点 public Node parent; public int FCost { get { return gCost + hCost; } } public Node(bool canWalk, Vector3 worldPos, int x, int y) { CanWalk = canWalk; WorldPos = worldPos; gridX = x; gridY = y; } } 
管理员
0
0
0
分享
上一篇: 传奇服务器+技能cd修改器,CD登陆器KEY文件修改教程+配套工具_【传奇爱好者】...
下一篇: 使用脚本得到当前的时间函数
评论
历史记录
回顶部
浏览时间 游戏名称 游戏IP 开区网址
注册GM1论坛账号
  • 上传头像
注册

已有账号,

微信扫码登录
重置密码
重置密码

注册

绑定关联手机号
关联手机号