1. 格子节点管理类(主要寻路逻辑)
- 针对开启列表OpenList的排序次数进行优化,减少排序的次数。
- 针对开启列表OpenList和关闭列表CloseList进行的判是否存在该节点进行优化,用一个数组记录已经在列表的格子,因为数组查找的效率比较高,用空间换时间。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
public class AStarOptimizeMgr : BaseSingleton<AStarOptimizeMgr>
{
private int m_Width;
private int m_Height;
private AStarNode[,] m_Nodes;
public AStarNode[,] Nodes
{
get {
return m_Nodes; }
}
private List<AStarNode> m_OpenList = new List<AStarNode>();
private List<AStarNode> m_CloseList = new List<AStarNode>();
private int m_RecordSortNum;
private int m_CalculateOrderNum;
private AStarNode[,] m_RecordNodes;
public void InitMapInfo(int width, int height)
{
Debug.Log("InitMapInfo");
m_Width = width;
m_Height = height;
if (m_Nodes == null)
{
m_Nodes = new AStarNode[width, height];
m_RecordNodes = new AStarNode[width, height];
}
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
AStarNode pNode;
if (i == 0 || i == width - 1 || j == 0 || j == height - 1)
{
pNode = new AStarNode(i, j, E_Node_Type.Boundary);
}
else
{
E_Node_Type eType = _GetRandRomNodeType();
pNode = new AStarNode(i, j, eType);
}
m_Nodes[i, j] = pNode;
}
}
}
public List<AStarNode> CalculateFindPath(Vector2Int startPos, Vector2Int endPos)
{
int iStartX = startPos.x;
int iStartY = startPos.y;
int iEndX = endPos.x;
int iEndY = endPos.y;
if (_IsOverBound(iStartX, iStartY) || _IsOverBound(iEndX, iEndY))
{
Debug.LogError("所在点超出界限");
return null;
}
AStarNode pStartNode = m_Nodes[iStartX, iStartY];
AStarNode pEndNode = m_Nodes[iEndX, iEndY];
if (pStartNode.type == E_Node_Type.Stop || pEndNode.type == E_Node_Type.Stop)
{
Debug.LogError("所在点是阻挡点,不合规范");
return null;
}
m_CalculateOrderNum = 0;
m_RecordSortNum = 0;
m_OpenList.Clear();
m_CloseList.Clear();
pStartNode.nodeParent = null;
pStartNode.f = 0;
pStartNode.g = 0;
pStartNode.h = 0;
m_CloseList.Add(pStartNode);
m_RecordNodes[iStartX, iStartY] = pStartNode;
AStarNode pCurrenNode = pStartNode;
float fTime = Time.realtimeSinceStartup;
while (pCurrenNode != pEndNode)
{
_AddNearNodeToOpenList(pCurrenNode.x - 1, pCurrenNode.y - 1, 1.4f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x - 1, pCurrenNode.y, 1.0f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x - 1, pCurrenNode.y + 1, 1.4f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x, pCurrenNode.y - 1, 1.0f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x, pCurrenNode.y + 1, 1.0f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x + 1, pCurrenNode.y - 1, 1.4f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x + 1, pCurrenNode.y, 1.0f, pCurrenNode, endPos);
_AddNearNodeToOpenList(pCurrenNode.x + 1, pCurrenNode.y + 1, 1.4f, pCurrenNode, endPos);
if (m_OpenList.Count == 0)
{
Debug.LogError("死路");
return null;
}
if (m_RecordSortNum <= 0)
{
m_OpenList.Sort((x, y) => x.f.CompareTo(y.f));
m_CalculateOrderNum++;
m_RecordSortNum = m_OpenList.Count;
}
else
{
m_RecordSortNum--;
}
pCurrenNode = m_OpenList[0];
m_CloseList.Add(pCurrenNode);
m_OpenList.RemoveAt(0);
}
Debug.LogFormat("用时:{0}", Time.realtimeSinceStartup - fTime);
Debug.Log("排序次数" + m_CalculateOrderNum);
List<AStarNode> lstPathNode = new List<AStarNode>();
AStarNode pNode = pEndNode;
while (pNode != null)
{
lstPathNode.Add(pNode);
pNode = pNode.nodeParent;
}
lstPathNode.Reverse();
return lstPathNode;
}
private E_Node_Type _GetRandRomNodeType()
{
int iRandNum = UnityEngine.Random.Range(0, 10);
if (iRandNum >= 0 && iRandNum < 8)
return E_Node_Type.Pass;
else
return E_Node_Type.Stop;
}
private bool _IsOverBound(int x, int y)
{
if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
return true;
else
return false;
}
private bool _IsCanPass(int x, int y)
{
E_Node_Type type = m_Nodes[x, y].type;
if (type == E_Node_Type.Stop)
return false;
else
return true;
}
private int _GetManhattanDistance(int x, int y, Vector2Int endPos)
{
int iHorizontal = Mathf.Abs(endPos.x - x);
int iVertical = Mathf.Abs(endPos.y - y);
return iHorizontal + iVertical;
}
private void _AddNearNodeToOpenList(int x, int y, float g, AStarNode parentNode, Vector2Int endPos)
{
if (!_IsOverBound(x, y) && _IsCanPass(x, y))
{
AStarNode pNode = m_Nodes[x, y];
if (m_RecordNodes[x, y] != pNode)
{
pNode.nodeParent = parentNode;
pNode.g = parentNode != null ? g + parentNode.g : g;
pNode.h = _GetManhattanDistance(x, y, endPos);
pNode.f = pNode.g + pNode.h;
if (m_RecordSortNum > 0)
{
if (pNode.f < m_OpenList[0].f)
m_OpenList.Insert(0, pNode);
else
m_OpenList.Add(pNode);
}
else
{
m_OpenList.Add(pNode);
}
m_RecordNodes[x, y] = pNode;
}
}
}
}