1. Grid node management class (main pathfinding logic)
Optimize the sorting times of OpenList to reduce the number of sorting times.
Optimize the judgment of whether the node exists in the open list OpenList and the closed list CloseList, and use an array to record the grids already in the list, because the efficiency of array search is relatively high, and space is exchanged for time.
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;
}
}
}
}