需要设置地图尺寸,设置绘制路点物体,
基于判断周围物体的碰撞体来识别障碍,
在别的脚本中调用AStarSearchPath(Vector3 startPos, Vector3 endPos)方法即可
using System.Collections.Generic;
using UnityEngine;
public class AStar : MonoBehaviour
{
//开启列表(任务列表),存储当前节点,父节点
private Dictionary<Vector2Int, Vector2Int> openDic = new Dictionary<Vector2Int, Vector2Int>();
//关闭列表(查询过的点不再查询)
private List<Vector2Int> closeList = new List<Vector2Int>();
//g是父节点步长加上当前节点步长所得,累加
private Dictionary<Vector2Int, float> costDic = new Dictionary<Vector2Int, float>();
//h是当前节点到终点的消耗,计算所得,值固定
private Dictionary<Vector2Int, float> heuristicDic = new Dictionary<Vector2Int, float>();
//A*算法主函数
public List<Vector2Int> AStarSearchPath(Vector2Int startPos,Vector2Int endPos)
{
//初始化
openDic.Clear();
closeList.Clear();
costDic.Clear();
heuristicDic.Clear();
heuristicDic.Add(startPos, GetHeuristic(startPos, endPos));
costDic.Add(startPos, 0);
openDic.Add(startPos,startPos);
closeList.Add(startPos);
while (costDic.Count > 0)
{
//在openList列表中找出F最小的点
Vector2Int current = GetShortestPos();
if (current.Equals(endPos))
break;
//计算当前节点的相邻节点
List<Vector2Int> neighbors = GetNeighbors(current);
//循环邻居
foreach(Vector2Int next in neighbors)
{
//如果对象不存在与closeList列表中
if (!closeList.Contains(next))
{
//难点!!!
costDic.Add(next, costDic[current] + GetCost(current, next));
heuristicDic.Add(next, costDic[next] + GetHeuristic(next, endPos));
openDic.Add(next, current);
closeList.Add(next);
}
}
}
List<Vector2Int> pathList = ShowPath(startPos, endPos);
pathList.Reverse(); //翻转,排序正确
return pathList;
}
public int mapSize;
//获得相邻点
private List<Vector2Int> GetNeighbors(Vector2Int point)
{
Vector2Int up = point + Vector2Int.up;
Vector2Int down = point + Vector2Int.down;
Vector2Int left = point + Vector2Int.left;
Vector2Int right = point + Vector2Int.right;
Vector2Int upleft = point + Vector2Int.up + Vector2Int.left;
Vector2Int upright = point + Vector2Int.up + Vector2Int.right;
Vector2Int downleft = point + Vector2Int.down + Vector2Int.left;
Vector2Int downright = point + Vector2Int.down + Vector2Int.right;
List<Vector2Int> neighbourList = new List<Vector2Int>();
if (up.y < mapSize && !Physics2D.OverlapCircle(up, 0.1f))
neighbourList.Add(up);
if (down.y >= 0 && !Physics2D.OverlapCircle(down, 0.1f))
neighbourList.Add(down);
if (left.x >= 0 && !Physics2D.OverlapCircle(left, 0.1f))
neighbourList.Add(left);
if (right.x < mapSize && !Physics2D.OverlapCircle(right, 0.1f))
neighbourList.Add(right);
if (upleft.x > 0 && upleft.y < mapSize
&& !Physics2D.OverlapCircle(upleft, 0.1f))
neighbourList.Add(upleft);
if (upright.x < mapSize && upright.y < mapSize
&& !Physics2D.OverlapCircle(upright, 0.1f))
neighbourList.Add(upright);
if (downleft.x > 0 && downleft.y > 0
&& !Physics2D.OverlapCircle(downleft, 0.1f))
neighbourList.Add(downleft);
if (downright.x < mapSize && downright.y > 0
&& !Physics2D.OverlapCircle(downright, 0.1f))
neighbourList.Add(downright);
return neighbourList;
}
//获取当前点到相邻点的步长,1或1.4
private float GetCost(Vector2Int current, Vector2Int next)
{
if (Mathf.Abs(current.x - next.x) == 1 && Mathf.Abs(current.y - next.y) == 1)
return 1.4f;
else
return 1;
}
//获取当前位置到终点的消耗(距离)
private float GetHeuristic(Vector2Int posA, Vector2Int posB)
{
return Mathf.Abs(posA.x - posB.x) + Mathf.Abs(posA.y - posB.y);
}
//获取任务(开启)列表openList里最少消耗的坐标
private Vector2Int GetShortestPos()
{
//定义一个键值对,初始化
KeyValuePair<Vector2Int, float> shortest =
new KeyValuePair<Vector2Int, float>(Vector2Int.zero, int.MaxValue);
foreach(var item in heuristicDic)
if(item.Value < shortest.Value)
shortest = item;
heuristicDic.Remove(shortest.Key);
return shortest.Key;
}
//画路径
public GameObject pathImage;
private List<Vector2Int> ShowPath(Vector2Int startPos, Vector2Int endPos)
{
List<Vector2Int> pathList = new List<Vector2Int>();
Vector2Int current = endPos;
pathList.Add(current);
while (current != startPos)
{
Vector2Int next = openDic[current];
pathList.Add(next);
current = next;
}
return pathList;
}
}