最近两天刚好有空研究了下游戏中的自动寻路功能,收获颇丰,感觉用相应的算法去解决相应的问题真的非常重要啊!至少比自己想的流水账逻辑流程管用。看来以后得花多点时间研究下算法方面的知识了。
游戏中的自动寻路,顾名思义就是找路,从地图找到从起点到终点的可行最短路径。既然是从地图找路,那么地图就应该是可数据化的,要不怎么找呢。
所以自动寻路的有两个重点是分别是地图数据化和搜索算法。
地图数据化,3D游戏地图有点复杂,还没研究,今天先看看2D游戏的。比如,搞一张九宫格式的地图,那么每个格子至少需要有这样的数据,格子的坐标、是路还是墙(根据具体情况格子还可以拓展其他属性)。然后有了这份数据化的地图后,寻路就变成了从一个格子移动到另一个格子的过程。
搜索算法,深度优先搜索(DFS)和广度优先搜索(BFS)算法,通常我们说DFS用栈方式实现,BFS用队列方式实现,为什么呢,下面我们来看看。
栈:起点P,将邻接点A、B、C、D存入栈,标记P为已查找,然后D出栈,得邻接点D1、D2、D3、D4, 栈变成B、C、D1、D2、D3、D4,继续D4出栈得新栈B、C、D1、D2、D3、d1、d2、d3、d4…。
邻接点:不考虑斜角方向,有上下左右四个。
粗糙理解讲下就是队列是从根节点开始,搜索所有子节点,然后搜索所有子节点的所有子节点;而栈是从根节点开始,搜索所有子节点,选择某个子节点搜索所有子节点,找不到则回溯父节点继续操作(参考二叉树辅助图理解)。其实从上面来看,无论是栈还是队列,对某个点都是只能访问一次的,访问后立即出栈或出队。如果没处理好,出现重复访问某个点的话,容易出现死循环。
运用到游戏中,那么起点就是二叉树的根节点,终点就是某个子节点,自动寻路就是找到从根节点到子节点的一条连接线。根节点每连接一个子节点时就记录下长度,最后根据长度就可以求出最短路径了。
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
public class CPathFind : MonoBehaviour {
// 自定义地图,1可行,0障碍
private const int Row = 8, Col = 9;
private int[,] MapDataArr = new int[Row, Col]
{
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 0, 0, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 0, 0, 1, 1},
{1, 1, 1, 0, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 1, 1, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
};
// 每个地图点数据化
private class CMapPoint
{
public int x;
public int y;
public int abstacle;
public bool isFind = false;
public int moveDis = 0;
public CMapPoint fatherPoint;
public CMapPoint(int x, int y, CMapPoint fp = null)
{
this.x = x;
this.y = y;
fatherPoint = fp;
}
}
public GameObject wBlockPrefab;
public GameObject bBlockPrefab;
public GameObject playerPrefab;
public GameObject blockGroupObj;
private bool isMove = false;
private int leastDis = 10000;
private int findCount = 0;
private CMapPoint endTargetPoint = new CMapPoint(0, 0);
private CMapPoint moveTargetPoint = new CMapPoint(0, 0);
private CMapPoint playerPoint = new CMapPoint(0, 0);
private List MapPointList = new List();
private List MovePointList = new List();
private List OpenList = new List();
private List CloseList = new List();
void Start () {
CreateMap();
}
void Update () {
PlayerMove();
}
void OnDestroy()
{
for (int i = 0; i < blockGroupObj.transform.childCount; i++)
{
GameObject.Destroy(blockGroupObj.transform.GetChild(i).gameObject);
}
}
void CreateMap()
{
for (int r = 0; r < MapDataArr.GetLength(0); r++)
{
for (int c = 0; c < MapDataArr.GetLength(1); c++)
{
CMapPoint mp = new CMapPoint(c, r) {
abstacle = MapDataArr[r, c]
};
MapPointList.Add(mp);
GameObject blockPrefab = null;
if (MapDataArr[r, c] == 1)
blockPrefab = wBlockPrefab;
else
blockPrefab = bBlockPrefab;
GameObject blockObj = GameObject.Instantiate(blockPrefab, Vector3.zero, Quaternion.identity) as GameObject;
blockObj.name = r + "," + c;
blockObj.transform.SetParent(blockGroupObj.transform);
blockObj.transform.localScale = Vector3.one;
// 左下角为原点
blockObj.transform.localPosition = new Vector3(c * 60, r * 60, 0);
blockObj.SetActive(true);
blockObj.GetComponent
》》》》戳我下载完整项目》》》》