简介
A* 算法 ,用于寻路。可以寻找到最短路径。由于本系列是介绍 如何只用IF框架的各个模块,并非探究各个模块的实现原理。所以本文着重讲如何使用IF框架中的A*寻路模块。
测试源码
using UnityEngine;
using IFramework.Astar; //引入IF框架 A* 空间
public class MapGrid : MonoBehaviour
{
public GameObject r_player;
public GameObject r_Enemy;
//********构建地图 部分********//
public LayerMask r_wallPlayer;
public Vector2 mapSize;
Node[,] aStarMap;
Vector3 startPosOfWoldPos;
Vector3 buffeV2;
//********* 引入 IF框架,进行A* 计算********//
AStarMap2X AMape = new AStarMap2X(); // 该类是 IF框架中 A* 模块的类,可以理解为 地图类
AStarSeacher<AStarNode2X, AStarMap2X> sear; // 该类IF框架中 A* 模块的类,可以理解为 搜寻者类。
private void Start()
{
//********构建地图 部分********//
int x = Mathf.FloorToInt(mapSize.x);
int y = Mathf.FloorToInt(mapSize.y);
aStarMap = new Node[x, y];
startPosOfWoldPos = transform.position + new Vector3(0.4f - mapSize.x / 2, 0, 0.4f - mapSize.y / 2);
buffeV2 = Vector2.zero;
CreateGride();
//********* 引入 IF框架,进行A* 计算********//
AMape.ReadMap((value_) =>
{
if (value_.isWalk)
{
return AStarNodeType.Walkable;
}
else
{
return AStarNodeType.Wall;
}
}, aStarMap, true);
sear = new AStarSeacher<AStarNode2X, AStarMap2X>();
sear.LoadMap(AMape);
SearchPaht(woldPosTomapPos(r_Enemy.transform.position ),woldPosTomapPos(r_player.transform.position ));
}
// 初始化地图方法
private void CreateGride()
{
for (int i = 0; i < aStarMap.GetLength(0); i++)
{
for (int j = 0; j < aStarMap.GetLength(1); j++)
{
buffeV2.x = startPosOfWoldPos.x + i;
buffeV2.z = startPosOfWoldPos.z + j;
aStarMap[i, j] = new Node(buffeV2, !(Physics.CheckSphere(buffeV2, 0.4f, r_wallPlayer)));
}
}
}
// 绘制 Cube
private void OnDrawGizmos()
{
if (aStarMap != null)
{
foreach (Node item in aStarMap)
{
Gizmos.color = item.isWalk ? Color.white : Color.red;
if (item.isPath)
Gizmos.color = Color.yellow;
Gizmos.DrawCube(item.woldPos, Vector3.one * 0.8f);
}
}
}
// 将世界位置转化为 地图位置。
public Vector2 woldPosTomapPos(Vector3 targetPos)
{
Vector2 result = Vector2.zero;
Vector3 delta = targetPos - startPosOfWoldPos;
result.x = Mathf.Clamp(Mathf.RoundToInt(delta.x), 0, mapSize.x - 1);
result.y = Mathf.Clamp(Mathf.RoundToInt(delta.z), 0, mapSize.y - 1);
return result;
}
// 计算 最短 路径。
public void SearchPaht(Vector2 nowPos, Vector2 aimPos)
{
try
{
AStarNode2X[] pathArray = sear.Search(AMape[(int)nowPos.x, (int)nowPos.y], AMape[(int)aimPos.x, (int)aimPos.y]);
foreach (var item in aStarMap)
{
item.isPath = false;
}
if(pathArray==null)
return;
foreach (var item in pathArray)
{
aStarMap[item.X, item.Y].isPath = true;
}
}
catch
{
print("MapIndex crossing boundary");
}
}
}
/// <summary>
/// 节点类,用于对对接IF框架的 地图节点。
/// </summary>
public class Node
{
public Vector3 woldPos; // 该节点在世界空间的位置
public Vector2 mapPos; // 该节点在地图中的位置
public bool isWalk; // 是否可以行走
public bool isPath; // 是否是返回路径
public Node() { }
public Node(Vector3 woldPos, bool isWalk)
{
this.woldPos = woldPos;
this.isWalk = isWalk;
}
}
运行效果:
image.png image.png
白色的是 可以行走区域,红色和的是 障碍区域,不可行走。 黄色的方块是 寻找出来的最短 路径。
源码说明
源代码 主要 内容 分为 两个部分:
- 构建可视化地图
- 计算最短路径
其中 构建可视化地图 属于 unity的基础。我用到的 API 可以通过 查阅 unity官方手册查询得到。本文 主要介绍 IF 框架的A* 模块使用,因此不多叙述。
A*模块主要类
AStarMap2X AMape ; // 该类是 IF框架中 A* 模块的类,可以理解为 地图类
AStarSeacher<AStarNode2X, AStarMap2X> sear; // 该类IF框架中 A* 模块的类,可以理解为 搜寻者类。
-
类名后面的 2x 表示 地图的维度,除了二维,还有三维。 这里为了演示简单,采用了二维计算。
-
AStarMap2x 类 是一个地图类 可以理解为 一个二维 地图。
public void ReadMap<T>(Func<T, AStarNodeType> func, T[,] arr, bool walkSideways = true);
此类 只需要 知道一个ReadMap 方法即可。
该方法 有三个参数,为了便于理解,将从参数二 开始介绍。
- 参数二:传入一个二维数组。作者这里传入了 一个自定义的
Node
二维数组。当然也可以传入一个int数组,因为是泛型,所以都支持。该数组 就是地图数据。 - 参数一:传入一个委托。该委托会 将会用于 处理 二维数组 中的值,比如什么情况下 将被标记为 “墙”。
public bool isWalk; // 是否可以行走
这里,我为Node
类定义 了isWalk
字段,用于区分 可行走/不可行走 区域。 - 参数三:用于设定 A* 寻路是否斜着行走。 默认True 就好。
个人猜测:ReadMap 会将 泛型类型二维数组的值,转化为 AStarNode2x 类型。从而形成一个AStarNode2X的二维数组至于是否是这样,咱们作为一个 接口调用员,并不重要。
- AStartSeacher 类 是一个 搜寻者类。 可以提供最短路径的搜索。是A*的核心算法封装而来。
- 构造注意:需要传入两个泛型,前者是一个节点类型,后者是一个map 类型。由于这里是 2维,所以 为:
AStarNode2X, AStarMap2X
。 -
LoadMap函数:
public void LoadMap(Map map);
用于 载入 地图。为 路径查找提供数据支持。 -
Search函数:
public Node[] Search(Node start, Node end);
用于 查找 开始节点,结束节点之间的 最短路径。 返回一个 节点 数组。该返回值 中 按顺序 存放着 路径的 所有节点。
我们拿到 “路径”后,就可以根据 自己的需要进行 转化。如何 在世界 空间和 二维数组地图间 经行 转化 ,可以参考 我前面 的源码。
结尾
以上内容是 作者个人的理解,如有错误,欢迎指出。
顺便给出OnClick大佬自己 写的文档地址:002AStar寻路模块
如果对 IF框架有其他看法,也欢迎大家 进群交流。
网友评论