211 lines
6.5 KiB
C#
211 lines
6.5 KiB
C#
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using static UnityEngine.UI.Image;
|
||
|
||
namespace Ether
|
||
{
|
||
public class AStar
|
||
{
|
||
private AStarNode[,] gridNode;
|
||
|
||
private int gridWidth;
|
||
private int gridHeight;
|
||
|
||
private Vector2Int origin;
|
||
|
||
public AStar(int gridWidth, int gridHeight, List<Vector2Int> obstacleList, Vector2Int origin = default)
|
||
{
|
||
this.gridWidth = gridWidth;
|
||
this.gridHeight = gridHeight;
|
||
this.origin = origin;
|
||
|
||
SetData(gridWidth, gridHeight);
|
||
|
||
foreach (var obstaclePos in obstacleList)
|
||
{
|
||
AStarNode node = GetGridNode(obstaclePos.x - origin.x, obstaclePos.y - origin.x);
|
||
node.isObstacle = true;
|
||
}
|
||
}
|
||
|
||
private void SetData(int gridWidth, int gridHeight)
|
||
{
|
||
gridNode = new AStarNode[gridWidth, gridHeight];
|
||
|
||
for (int x = 0; x < gridWidth; x++)
|
||
{
|
||
for (int y = 0; y < gridHeight; y++)
|
||
{
|
||
gridNode[x, y] = new AStarNode(new Vector2Int(x, y));
|
||
}
|
||
}
|
||
}
|
||
|
||
public AStarNode GetGridNode(int xPos, int yPos)
|
||
{
|
||
if (xPos < gridWidth && yPos < gridHeight)
|
||
{
|
||
return gridNode[xPos, yPos];
|
||
}
|
||
Debug.Log("超出寻路网格范围");
|
||
return null;
|
||
}
|
||
|
||
public void Reset(int gridWidth, int gridHeight, List<Vector2Int> obstacleList)
|
||
{
|
||
this.gridWidth = gridWidth;
|
||
this.gridHeight = gridHeight;
|
||
|
||
SetData(gridWidth, gridHeight);
|
||
|
||
foreach (var obstaclePos in obstacleList)
|
||
{
|
||
AStarNode node = GetGridNode(obstaclePos.x, obstaclePos.y);
|
||
node.isObstacle = true;
|
||
}
|
||
}
|
||
|
||
private List<AStarNode> openNodeList = new List<AStarNode>(); //当前选中Node周围的8个点
|
||
private HashSet<AStarNode> closedNodeList = new HashSet<AStarNode>(); //所有被选中的点
|
||
|
||
private bool isPathFound;
|
||
|
||
private AStarNode startNode;
|
||
private AStarNode targetNode;
|
||
|
||
public void BuildPath(Vector2Int startPos, Vector2Int endPos, Stack<Vector2Int> stepStack)
|
||
{
|
||
openNodeList.Clear();
|
||
closedNodeList.Clear();
|
||
isPathFound = false;
|
||
|
||
startNode = GetGridNode(startPos.x - origin.x, startPos.y - origin.y);
|
||
|
||
targetNode = GetGridNode(endPos.x - origin.x, endPos.y - origin.y);
|
||
|
||
if (startNode == null || targetNode == null)
|
||
{
|
||
string str = (startNode == null && targetNode == null) ? startPos + "和" + endPos.x :
|
||
(startNode == null ? startPos.ToString() : endPos.ToString());
|
||
Debug.LogError($"找不到对应的网格点:{str}");
|
||
return;
|
||
}
|
||
|
||
//查找最短路径
|
||
if (FindShortestPath() && stepStack != null)
|
||
{
|
||
AStarNode nextNode = targetNode;
|
||
|
||
while (nextNode != null)
|
||
{
|
||
stepStack.Push(nextNode.gridPosition + origin);
|
||
nextNode = nextNode.parentNode;
|
||
}
|
||
}
|
||
}
|
||
|
||
private bool FindShortestPath()
|
||
{
|
||
//添加起点
|
||
openNodeList.Add(startNode);
|
||
|
||
while (openNodeList.Count > 0)
|
||
{
|
||
//节点排序,Node内涵比较函数
|
||
openNodeList.Sort();
|
||
|
||
AStarNode closeNode = openNodeList[0];
|
||
|
||
openNodeList.RemoveAt(0);
|
||
closedNodeList.Add(closeNode);
|
||
|
||
if (closeNode == targetNode)
|
||
{
|
||
isPathFound = true;
|
||
break;
|
||
}
|
||
|
||
//计算周围8个Node补充到OpenList
|
||
EvaluateNeighbourNodes(closeNode);
|
||
}
|
||
|
||
return isPathFound;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 评估周围8个点,并生成对应消耗值
|
||
/// </summary>
|
||
/// <param name="currentNode"></param>
|
||
private void EvaluateNeighbourNodes(AStarNode currentNode)
|
||
{
|
||
Vector2Int currentNodePos = currentNode.gridPosition;
|
||
AStarNode validNeighbourNode;
|
||
|
||
for (int x = -1; x <= 1; x++)
|
||
{
|
||
for (int y = -1; y <= 1; y++)
|
||
{
|
||
if (x == 0 && y == 0)
|
||
continue;
|
||
|
||
validNeighbourNode = GetValidNeighbourNode(currentNodePos.x + x, currentNodePos.y + y);
|
||
|
||
if (validNeighbourNode != null)
|
||
{
|
||
if (!openNodeList.Contains(validNeighbourNode))
|
||
{
|
||
validNeighbourNode.gCost = currentNode.gCost + GetDistance(currentNode, validNeighbourNode);
|
||
validNeighbourNode.hCost = GetDistance(validNeighbourNode, targetNode);
|
||
//链接父节点
|
||
validNeighbourNode.parentNode = currentNode;
|
||
openNodeList.Add(validNeighbourNode);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 找到有效的Node,非障碍,非已选择
|
||
/// </summary>
|
||
/// <param name="x"></param>
|
||
/// <param name="y"></param>
|
||
/// <returns></returns>
|
||
private AStarNode GetValidNeighbourNode(int x, int y)
|
||
{
|
||
if (x >= gridWidth || y >= gridHeight || x < 0 || y < 0)
|
||
return null;
|
||
|
||
AStarNode neighbourNode = GetGridNode(x, y);
|
||
|
||
if (neighbourNode.isObstacle || closedNodeList.Contains(neighbourNode))
|
||
return null;
|
||
else
|
||
return neighbourNode;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 返回两点距离值
|
||
/// </summary>
|
||
/// <param name="nodeA"></param>
|
||
/// <param name="nodeB"></param>
|
||
/// <returns>14的倍数+10的倍数</returns>
|
||
private int GetDistance(AStarNode nodeA, AStarNode nodeB)
|
||
{
|
||
int xDistance = Mathf.Abs(nodeA.gridPosition.x - nodeB.gridPosition.x);
|
||
int yDistance = Mathf.Abs(nodeA.gridPosition.y - nodeB.gridPosition.y);
|
||
|
||
if (xDistance > yDistance)
|
||
{
|
||
return 14 * yDistance + 10 * (xDistance - yDistance);
|
||
}
|
||
return 14 * xDistance + 10 * (yDistance - xDistance);
|
||
}
|
||
|
||
}
|
||
}
|