定义每个节点的信息
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WayPoint : MonoBehaviour
{
public bool isExplore;
public WayPoint exploreForm;//储存父节点
private void Awake()
{
Debug.Log(gameObject.name+" : "+GetPoint());
}
public Vector2Int GetPoint()//返回 int 类型的 vector 二维向量 物体在世界的坐标
{
return new Vector2Int
(
Mathf.RoundToInt(gameObject.transform.position.x),// Mathf.RoundToInt返回舍入为最近整数的 四舍五入
Mathf.RoundToInt(gameObject.transform.position.z)
) ;
}
}
/*mathf. .RoundToInt ()
遇到偶数会返回偶数。
传入11.5f 的结果是 12
传入10.5f 的结果是 10*/
创建地图并找到最短路径
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using static MapManager;
using static UnityEngine.RuleTile.TilingRuleOutput;
public class MapCreate : MonoBehaviour
{
[Header("Map Data")]
public GameObject tilpObject;
public Vector2 maxSize;
public UnityEngine.Transform storageParter;
public Vector2 startPoint;
public Vector2 endPoint;
Queue<WayPoint> queue=new Queue<WayPoint>();//储存waypoint类的队列 先进先出
public Dictionary<Vector2Int,WayPoint> wayPointDict=new Dictionary<Vector2Int, WayPoint>();
Vector2Int[] directions =
{
Vector2Int.up, Vector2Int.down,Vector2Int.left,Vector2Int.right
};
public bool isRunning=true;
WayPoint searchCenter;
public static List<WayPoint> pathList= new List<WayPoint>();//起始点到终点的最佳路径
Vector3 newPos;
public GameObject startObject;
public GameObject endObject;
private void Awake()
{
GenerateMap();
LoadAllWayPoint();
StartFindPath();
}
private void StartFindPath()
{
BFS();// 宽度优先算法 找到终点
CreatePath();//根据 终点 反推找到 起始点
}
//生成地图 生成初始点 和结束点
void GenerateMap()
{
//生成地图 遍历数组
for (int i = 0; i < maxSize.x; i++)//行 代表 x
{
for (int j = 0; j < maxSize.y; j++)// 列 代表 y
{
newPos=new Vector3(-maxSize.x/2-3.5f+3*j, 0, -maxSize.y-3.5f/2+3*i);//0,0为原点生成 居中在镜头中
var spawnTile = Instantiate(tilpObject, newPos, Quaternion.Euler(0, 0, 0), storageParter);// Quaternion.Euler(0, 0, 0) 旋转0度
spawnTile.gameObject.name=string.Format("({0}{1})", i, j);
spawnTile.GetComponentInChildren<TextMeshPro>().text=string.Format("({0}{1})",i,j);
if(i==startPoint.x&&j==startPoint.y)
{
spawnTile.GetComponent<MeshRenderer>().material.color = Color.blue;
spawnTile.GetComponentInChildren<TextMeshPro>().color=Color.blue;
startObject= spawnTile;
}
if (i==endPoint.x&&j==endPoint.y)
{
spawnTile.GetComponent<MeshRenderer>().material.color = Color.red;
spawnTile.GetComponentInChildren<TextMeshPro>().color=Color.red;
endObject= spawnTile;
}
}
}
}
//遍历每个节点的四邻节点
void ExploreAround()
{
if(isRunning==false) return;
foreach(Vector2Int diretion in directions)
{
var exporeArounds = searchCenter.GetPoint()+diretion*3;//必须*3 应为设置的间隔为3.5 要不然字典没有对于键
//捕获异常 在容易出错的地方使用 避免游戏出错终止 列如数组超出范围
try
{
var neighbour = wayPointDict[exporeArounds];
if (neighbour.isExplore==true||queue.Contains(neighbour))//已经被检测 不在运行
{
Debug.Log("捕获异常 以检测");
}
else
{
neighbour.exploreForm=searchCenter;
queue.Enqueue(neighbour);
// searchCenter.gameObject.GetComponentInChildren<TextMeshPro>().color=Color.black;
}
}
catch
{
Debug.Log("异常 ");
}
}
}
//储存所有的 物体的坐标 对于 坐标值
void LoadAllWayPoint()
{
var wayPoints=FindObjectsOfType<WayPoint>();
foreach(WayPoint wayPoint in wayPoints)
{
var tempWayPoint = wayPoint.GetPoint();
if (wayPointDict.ContainsKey(tempWayPoint))//判断字典中 键是否有对应值 Vector2Int有没有对应的 WayPoint
{
Debug.Log("没有字典对于值");
}
else
{
wayPointDict.Add(tempWayPoint, wayPoint);
Debug.Log("字典中世界位置"+tempWayPoint);
}
}
Debug.Log("加载全部节点到字典中");
}
void BFS()
{
Debug.Log("BFS 运行");
queue.Enqueue(startObject.GetComponent<WayPoint>());
while(queue.Count > 0&&isRunning)
{
Debug.Log("BFS 正在寻找终点");
searchCenter=queue.Dequeue();//移除节点
StopIfSearchEnd();//判断是否找到终点
ExploreAround();
searchCenter.isExplore= true;
}
}
//找到终点就结束
void StopIfSearchEnd()
{
if(searchCenter==endObject.GetComponent<WayPoint>())
{
isRunning= false;
}
}
//反推终点找起始点
void CreatePath()
{
pathList.Add(endObject.GetComponent<WayPoint>());
WayPoint prePoint = endObject.GetComponent<WayPoint>().exploreForm;
while(prePoint != startObject.GetComponent<WayPoint>())
{
//改变颜色
prePoint.GetComponent<MeshRenderer>().material.color=Color.yellow;
pathList.Add(prePoint);
prePoint= prePoint.exploreForm;
}
pathList.Add(startObject.GetComponent<WayPoint>());
pathList.Reverse();//逆转顺序
}
private void Update()
{
if(Input.GetKey(KeyCode.Space))
{
wayPointDict.Clear();
queue.Clear();
pathList.Clear();
isRunning=true;
LoadAllWayPoint();
StartFindPath();
}
}
}
敌人根据地图创建中的路径移动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMover : MonoBehaviour
{
public float waitTime;
WaitForSeconds waitForSeconds;
private void Awake()
{
waitForSeconds=new WaitForSeconds(waitTime);
}
private void Start()
{
StartCoroutine(nameof(FindWayPointCorotine));
//StartCoroutine(FindWayPointCorotine());
}
private void Update()
{
if(Input.GetKeyUp(KeyCode.Escape))
{
StartCoroutine(nameof(FindWayPointCorotine));
}
}
IEnumerator FindWayPointCorotine()
{
foreach (var wayPoint in MapCreate.pathList)
{
transform.position = wayPoint.transform.position+new Vector3(0,1,0);
yield return waitForSeconds;
}
}
}
详细看
广度优先搜索算法在Unity网格地图中实现最短路径【解决篇】(含:字典、队列、Vector2Int、List和字符串拼接等问题)_哔哩哔哩_bilibili
分享a*寻路算法的网站