第一次提交
This commit is contained in:
86
Assets/Scripts/PathFinding/IPathFinder.cs
Normal file
86
Assets/Scripts/PathFinding/IPathFinder.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
|
||||
public delegate float OnCellCross(int cellIndex);
|
||||
|
||||
interface IPathFinder
|
||||
{
|
||||
|
||||
HeuristicFormula Formula
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool Diagonals
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
float HeavyDiagonalsCost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool HexagonalGrid
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
float HeuristicEstimate
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
int MaxSteps
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
float MaxSearchCost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
int CellGroupMask
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool IgnoreCanCrossCheck
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool IgnoreCellCost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool IncludeInvisibleCells
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
List<PathFinderNode> FindPath(CellNode start, CellNode end, out float cost, bool evenLayout);
|
||||
|
||||
void SetCalcMatrix(CellNode[] grid);
|
||||
|
||||
OnCellCross OnCellCross { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/IPathFinder.cs.meta
Normal file
11
Assets/Scripts/PathFinding/IPathFinder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c18851357144d9a4abcd3a53911deec7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Assets/Scripts/PathFinding/PathFinder.cs
Normal file
49
Assets/Scripts/PathFinding/PathFinder.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
public struct PathFinderNode
|
||||
{
|
||||
public float F;
|
||||
public float G;
|
||||
public float H; // f = gone + heuristic
|
||||
public int X;
|
||||
public int Y;
|
||||
public int PX; // Parent
|
||||
public int PY;
|
||||
}
|
||||
|
||||
public enum PathFinderNodeType
|
||||
{
|
||||
Start = 1,
|
||||
End = 2,
|
||||
Open = 4,
|
||||
Close = 8,
|
||||
Current = 16,
|
||||
Path = 32
|
||||
}
|
||||
|
||||
//<2F><><EFBFBD><EFBFBD><EFBFBD>㷨
|
||||
public enum HeuristicFormula
|
||||
{
|
||||
Manhattan = 1,
|
||||
MaxDXDY = 2,
|
||||
DiagonalShortCut = 3,
|
||||
Euclidean = 4,
|
||||
EuclideanNoSQR = 5,
|
||||
Custom1 = 6
|
||||
}
|
||||
|
||||
internal class ComparePFNode : IComparer<PathFinderNode>
|
||||
{
|
||||
public int Compare(PathFinderNode x, PathFinderNode y)
|
||||
{
|
||||
if (x.F > y.F)
|
||||
return 1;
|
||||
else if (x.F < y.F)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/PathFinder.cs.meta
Normal file
11
Assets/Scripts/PathFinding/PathFinder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2dca386ccf57f614eabc8c92bcc75b70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
478
Assets/Scripts/PathFinding/PathFinderFast.cs
Normal file
478
Assets/Scripts/PathFinding/PathFinderFast.cs
Normal file
@@ -0,0 +1,478 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static HxGame.PathFinding.IPathFinder;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
internal struct PathFinderNodeFast
|
||||
{
|
||||
public float F;
|
||||
// f = gone + heuristic
|
||||
public float G;
|
||||
public ushort PX;
|
||||
// Parent
|
||||
public ushort PY;
|
||||
public byte Status;
|
||||
public int Steps;
|
||||
}
|
||||
|
||||
public class PathFinderFast : IPathFinder
|
||||
{
|
||||
private CellNode[] mGrid = null; //<2F><><EFBFBD>нڵ<D0BD>
|
||||
private PriorityQueueB<int> mOpen = null;
|
||||
private List<PathFinderNode> mClose = new List<PathFinderNode>();
|
||||
private HeuristicFormula mFormula = HeuristicFormula.Manhattan; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private bool mDiagonals = true; //<2F>Ƿ<EFBFBD><C7B7><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD>
|
||||
private bool mHexagonalGrid = false; //<2F>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>θ<EFBFBD><CEB8><EFBFBD>
|
||||
private float mHEstimate = 1; //<2F><><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4>
|
||||
private float mHeavyDiagonalsCost = 1.4f; //б<><D0B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private int mMaxSteps = 2000; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private float mMaxSearchCost = 100000; //<2F><><EFBFBD><EFBFBD>Ѱ·<D1B0><C2B7><EFBFBD><EFBFBD>
|
||||
private PathFinderNodeFast[] mCalcGrid = null;
|
||||
private byte mOpenNodeValue = 1;
|
||||
private byte mCloseNodeValue = 2;
|
||||
private OnCellCross mOnCellCross = null;
|
||||
|
||||
private float mH = 0;
|
||||
private int mLocation = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private int mNewLocation = 0; //<2F>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mLocationX = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mLocationY = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mNewLocationX = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mNewLocationY = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mGridX = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mGridY = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private ushort mGridXMinus1 = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-1
|
||||
private ushort mGridYLog2 = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD><EFBFBD>
|
||||
private bool mFound = false;
|
||||
|
||||
private sbyte[,] mDirection = new sbyte[8, 2]
|
||||
{
|
||||
{ 0, -1}, //bottom
|
||||
{ 1, 0}, //right
|
||||
{ 0, 1}, //top
|
||||
{ -1, 0}, //left
|
||||
{ 1, -1}, //right-bottom
|
||||
{ 1, 1}, //right-top
|
||||
{ -1, 1}, //left-top
|
||||
{ -1, -1}, //left-bottom
|
||||
};
|
||||
private readonly sbyte[,] mDirectionHex0 = new sbyte[6, 2]
|
||||
{
|
||||
{ 0, -1 }, //top
|
||||
{ 1, 0 }, //right
|
||||
{ 0, 1 }, //bottom
|
||||
{ -1, 0 }, //left
|
||||
{ 1, 1}, //right-bottom
|
||||
{ -1,1 } //left-bottom
|
||||
};
|
||||
private readonly sbyte[,] mDirectionHex1 = new sbyte[6, 2]
|
||||
{
|
||||
{ 0, -1 }, //top
|
||||
{ 1, 0 }, //right
|
||||
{ 0, 1 }, //bottom
|
||||
{ -1, 0 }, //left
|
||||
{ -1, -1 }, //left-top
|
||||
{ 1, -1} //right-top
|
||||
};
|
||||
private readonly int[] mCellSide0 = new int[6] {
|
||||
(int)CELL_SIDE.Bottom,
|
||||
(int)CELL_SIDE.BottomRight,
|
||||
(int)CELL_SIDE.Top,
|
||||
(int)CELL_SIDE.BottomLeft,
|
||||
(int)CELL_SIDE.TopRight,
|
||||
(int)CELL_SIDE.TopLeft
|
||||
};
|
||||
private readonly int[] mCellSide1 = new int[6] {
|
||||
(int)CELL_SIDE.Bottom,
|
||||
(int)CELL_SIDE.TopRight,
|
||||
(int)CELL_SIDE.Top,
|
||||
(int)CELL_SIDE.TopLeft,
|
||||
(int)CELL_SIDE.BottomLeft,
|
||||
(int)CELL_SIDE.BottomRight
|
||||
};
|
||||
private readonly int[] mCellBoxSides = new int[8] {
|
||||
(int)CELL_SIDE.Bottom,
|
||||
(int)CELL_SIDE.Right,
|
||||
(int)CELL_SIDE.Top,
|
||||
(int)CELL_SIDE.Left,
|
||||
(int)CELL_SIDE.BottomRight,
|
||||
(int)CELL_SIDE.TopRight,
|
||||
(int)CELL_SIDE.TopLeft,
|
||||
(int)CELL_SIDE.BottomLeft
|
||||
};
|
||||
|
||||
private int mEndLocation = 0; //<2F>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private float mNewG = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>gֵ
|
||||
private int mCellGroupMask = -1;
|
||||
private bool mIgnoreCanCrossCheck; //<2F><><EFBFBD><EFBFBD><EFBFBD>赲
|
||||
private bool mIgnoreCellCost; //<2F><><EFBFBD>Ը<EFBFBD><D4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
private bool mIncludeInvisibleCells;
|
||||
|
||||
public void SetCalcMatrix(CellNode[] grid)
|
||||
{
|
||||
if (grid == null)
|
||||
throw new Exception("Grid cannot be null");
|
||||
if (grid.Length != mGrid.Length)
|
||||
throw new Exception("SetCalcMatrix called with matrix with different dimensions. Call constructor instead.");
|
||||
mGrid = grid;
|
||||
|
||||
Array.Clear(mCalcGrid, 0, mCalcGrid.Length);
|
||||
ComparePFNodeMatrix comparer = (ComparePFNodeMatrix)mOpen.comparer;
|
||||
comparer.SetMatrix(mCalcGrid);
|
||||
}
|
||||
|
||||
public HeuristicFormula Formula
|
||||
{
|
||||
get { return mFormula; }
|
||||
set { mFormula = value; }
|
||||
}
|
||||
|
||||
public bool Diagonals
|
||||
{
|
||||
get { return mDiagonals; }
|
||||
set
|
||||
{
|
||||
mDiagonals = value;
|
||||
if (mDiagonals)
|
||||
mDirection = new sbyte[8, 2] {
|
||||
{ 0, -1 },
|
||||
{ 1, 0 },
|
||||
{ 0, 1 },
|
||||
{ -1, 0 },
|
||||
{ 1, -1 },
|
||||
{ 1, 1 },
|
||||
{ -1, 1 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
else
|
||||
mDirection = new sbyte[4, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
|
||||
}
|
||||
}
|
||||
|
||||
public float HeavyDiagonalsCost
|
||||
{
|
||||
get { return mHeavyDiagonalsCost; }
|
||||
set { mHeavyDiagonalsCost = value; }
|
||||
}
|
||||
|
||||
public bool HexagonalGrid
|
||||
{
|
||||
get { return mHexagonalGrid; }
|
||||
set { mHexagonalGrid = value; }
|
||||
}
|
||||
|
||||
public float HeuristicEstimate
|
||||
{
|
||||
get { return mHEstimate; }
|
||||
set { mHEstimate = value; }
|
||||
}
|
||||
|
||||
public float MaxSearchCost
|
||||
{
|
||||
get { return mMaxSearchCost; }
|
||||
set { mMaxSearchCost = value; }
|
||||
}
|
||||
|
||||
public int MaxSteps
|
||||
{
|
||||
get { return mMaxSteps; }
|
||||
set { mMaxSteps = value; }
|
||||
}
|
||||
|
||||
public int CellGroupMask
|
||||
{
|
||||
get { return mCellGroupMask; }
|
||||
set { mCellGroupMask = value; }
|
||||
}
|
||||
|
||||
public bool IgnoreCanCrossCheck
|
||||
{
|
||||
get { return mIgnoreCanCrossCheck; }
|
||||
set { mIgnoreCanCrossCheck = value; }
|
||||
}
|
||||
|
||||
public bool IgnoreCellCost
|
||||
{
|
||||
get { return mIgnoreCellCost; }
|
||||
set { mIgnoreCellCost = value; }
|
||||
}
|
||||
|
||||
public bool IncludeInvisibleCells
|
||||
{
|
||||
get { return mIncludeInvisibleCells; }
|
||||
set { mIncludeInvisibleCells = value; }
|
||||
}
|
||||
|
||||
public OnCellCross OnCellCross
|
||||
{
|
||||
get { return mOnCellCross; }
|
||||
set { mOnCellCross = value; }
|
||||
}
|
||||
|
||||
public PathFinderFast(CellNode[] grid, int gridWidth, int gridHeight)
|
||||
{
|
||||
if (grid == null)
|
||||
throw new Exception("Grid cannot be null");
|
||||
|
||||
mGrid = grid;
|
||||
mGridX = (ushort)gridWidth;
|
||||
mGridY = (ushort)gridHeight;
|
||||
mGridXMinus1 = (ushort)(mGridX - 1);
|
||||
mGridYLog2 = (ushort)Math.Log(mGridX, 2);
|
||||
|
||||
// This should be done at the constructor, for now we leave it here.
|
||||
if (Math.Log(mGridX, 2) != (int)Math.Log(mGridX, 2))
|
||||
throw new Exception("Invalid Grid, size in X must be power of 2");
|
||||
|
||||
if (mCalcGrid == null || mCalcGrid.Length != (mGridX * mGridY))
|
||||
mCalcGrid = new PathFinderNodeFast[mGridX * mGridY];
|
||||
|
||||
mOpen = new PriorityQueueB<int>(new ComparePFNodeMatrix(mCalcGrid));
|
||||
}
|
||||
|
||||
public List<PathFinderNode> FindPath(CellNode startCell, CellNode endCell, out float totalCost, bool evenLayout)
|
||||
{
|
||||
totalCost = 0;
|
||||
mFound = false;
|
||||
int evenLayoutValue = evenLayout ? 1 : 0;
|
||||
if (mOpenNodeValue > 250)
|
||||
{
|
||||
Array.Clear(mCalcGrid, 0, mCalcGrid.Length);
|
||||
mOpenNodeValue = 1;
|
||||
mCloseNodeValue = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mOpenNodeValue += 2;
|
||||
mCloseNodeValue += 2;
|
||||
}
|
||||
mOpen.Clear();
|
||||
mClose.Clear();
|
||||
|
||||
int maxi; //<2F>ܱ߸<DCB1><DFB8><EFBFBD><EFBFBD><EFBFBD>
|
||||
if (mHexagonalGrid)
|
||||
maxi = 6;
|
||||
else
|
||||
maxi = mDiagonals ? 8 : 4;
|
||||
|
||||
//mLocation = (startCell.row << mGridYLog2) + startCell.column;
|
||||
//mEndLocation = (endCell.row << mGridYLog2) + endCell.column;
|
||||
mLocation = (startCell.Y << mGridYLog2) + startCell.X;
|
||||
mEndLocation = (endCell.Y << mGridYLog2) + endCell.X;
|
||||
mCalcGrid[mLocation].G = 0;
|
||||
mCalcGrid[mLocation].F = mHEstimate;
|
||||
//mCalcGrid[mLocation].PX = (ushort)startCell.column;
|
||||
//mCalcGrid[mLocation].PY = (ushort)startCell.row;
|
||||
mCalcGrid[mLocation].PX = (ushort)startCell.X;
|
||||
mCalcGrid[mLocation].PY = (ushort)startCell.Y;
|
||||
mCalcGrid[mLocation].Status = mOpenNodeValue;
|
||||
mCalcGrid[mLocation].Steps = 0;
|
||||
|
||||
mOpen.Push(mLocation);
|
||||
while (mOpen.Count > 0)
|
||||
{
|
||||
mLocation = mOpen.Pop();
|
||||
|
||||
//<2F>Ƿ<EFBFBD><C7B7>ڷ<EFBFBD><DAB7><EFBFBD><EFBFBD>б<EFBFBD><D0B1>У<EFBFBD><D0A3><EFBFBD>ʾ<EFBFBD>Ѵ<EFBFBD><D1B4><EFBFBD><EFBFBD>˽ڵ<CBBD>
|
||||
if (mCalcGrid[mLocation].Status == mCloseNodeValue)
|
||||
continue;
|
||||
|
||||
if (mLocation == mEndLocation)
|
||||
{
|
||||
mCalcGrid[mLocation].Status = mCloseNodeValue;
|
||||
mFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
mLocationX = (ushort)(mLocation & mGridXMinus1);
|
||||
mLocationY = (ushort)(mLocation >> mGridYLog2);
|
||||
|
||||
//<2F><><EFBFBD><EFBFBD><EFBFBD>ܱ<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
bool hasSideCosts = false;
|
||||
float[] sideCosts = mGrid[mLocation].crossCost;
|
||||
if (!mIgnoreCellCost && sideCosts != null)
|
||||
hasSideCosts = true;
|
||||
|
||||
for (int i = 0; i < maxi; i++)
|
||||
{
|
||||
int cellSide;
|
||||
if (mHexagonalGrid)
|
||||
{
|
||||
if (mLocationX % 2 == evenLayoutValue)
|
||||
{
|
||||
mNewLocationX = (ushort)(mLocationX + mDirectionHex0[i, 0]);
|
||||
mNewLocationY = (ushort)(mLocationY + mDirectionHex0[i, 1]);
|
||||
cellSide = mCellSide0[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
mNewLocationX = (ushort)(mLocationX + mDirectionHex1[i, 0]);
|
||||
mNewLocationY = (ushort)(mLocationY + mDirectionHex1[i, 1]);
|
||||
cellSide = mCellSide1[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mNewLocationX = (ushort)(mLocationX + mDirection[i, 0]);
|
||||
mNewLocationY = (ushort)(mLocationY + mDirection[i, 1]);
|
||||
cellSide = mCellBoxSides[i];
|
||||
}
|
||||
|
||||
if (mNewLocationY >= mGridY || mNewLocationX >= mGridX)
|
||||
continue;
|
||||
|
||||
mNewLocation = (mNewLocationY << mGridYLog2) + mNewLocationX;
|
||||
CellNode nextCell = mGrid[mNewLocation];
|
||||
if (nextCell == null || (nextCell.cellType == MapManager.CellType.Obstacle && !mIgnoreCanCrossCheck))
|
||||
continue;
|
||||
|
||||
//if (!mIncludeInvisibleCells && !mGrid[mNewLocation].visible)
|
||||
// continue;
|
||||
|
||||
float gridValue = (nextCell.group & mCellGroupMask) != 0 ? 1 : 0;
|
||||
if (gridValue == 0)
|
||||
continue;
|
||||
|
||||
if (hasSideCosts)
|
||||
{
|
||||
gridValue = sideCosts[cellSide];
|
||||
if (gridValue <= 0)
|
||||
gridValue = 1;
|
||||
}
|
||||
|
||||
if (mOnCellCross != null)
|
||||
gridValue += mOnCellCross(mNewLocation);
|
||||
|
||||
if (!mHexagonalGrid && i > 3)
|
||||
mNewG = mCalcGrid[mLocation].G + gridValue * mHeavyDiagonalsCost;
|
||||
else
|
||||
mNewG = mCalcGrid[mLocation].G + gridValue;
|
||||
|
||||
if (mNewG > mMaxSearchCost || mCalcGrid[mLocation].Steps >= mMaxSteps)
|
||||
continue;
|
||||
|
||||
if (mCalcGrid[mNewLocation].Status == mOpenNodeValue || mCalcGrid[mNewLocation].Status == mCloseNodeValue)
|
||||
{
|
||||
if (mCalcGrid[mNewLocation].G <= mNewG)
|
||||
continue;
|
||||
}
|
||||
|
||||
mCalcGrid[mNewLocation].PX = mLocationX;
|
||||
mCalcGrid[mNewLocation].PY = mLocationY;
|
||||
mCalcGrid[mNewLocation].G = mNewG;
|
||||
mCalcGrid[mNewLocation].Steps = mCalcGrid[mLocation].Steps + 1;
|
||||
|
||||
//int dist = Math.Abs(mNewLocationX - endCell.column);
|
||||
int dist = Math.Abs(mNewLocationX - endCell.X);
|
||||
|
||||
switch (mFormula)
|
||||
{
|
||||
default:
|
||||
case HeuristicFormula.Manhattan:
|
||||
//mH = mHEstimate * (dist + Math.Abs(mNewLocationY - endCell.row));
|
||||
mH = mHEstimate * (dist + Math.Abs(mNewLocationY - endCell.Y));
|
||||
break;
|
||||
case HeuristicFormula.MaxDXDY:
|
||||
//mH = mHEstimate * (Math.Max(dist, Math.Abs(mNewLocationY - endCell.row)));
|
||||
mH = mHEstimate * (Math.Max(dist, Math.Abs(mNewLocationY - endCell.Y)));
|
||||
break;
|
||||
case HeuristicFormula.DiagonalShortCut:
|
||||
//float h_diagonal = Math.Min(dist, Math.Abs(mNewLocationY - endCell.row));
|
||||
//float h_straight = (dist + Math.Abs(mNewLocationY - endCell.row));
|
||||
float h_diagonal = Math.Min(dist, Math.Abs(mNewLocationY - endCell.Y));
|
||||
float h_straight = (dist + Math.Abs(mNewLocationY - endCell.Y));
|
||||
mH = (mHEstimate * 2) * h_diagonal + mHEstimate * (h_straight - 2 * h_diagonal);
|
||||
break;
|
||||
case HeuristicFormula.Euclidean:
|
||||
//mH = mHEstimate * (float)(Math.Sqrt(Math.Pow(dist, 2) + Math.Pow((mNewLocationY - endCell.row), 2)));
|
||||
mH = mHEstimate * (float)(Math.Sqrt(Math.Pow(dist, 2) + Math.Pow((mNewLocationY - endCell.Y), 2)));
|
||||
break;
|
||||
case HeuristicFormula.EuclideanNoSQR:
|
||||
//mH = mHEstimate * (float)(Math.Pow(dist, 2) + Math.Pow((mNewLocationY - endCell.row), 2));
|
||||
mH = mHEstimate * (float)(Math.Pow(dist, 2) + Math.Pow((mNewLocationY - endCell.Y), 2));
|
||||
break;
|
||||
}
|
||||
mCalcGrid[mNewLocation].F = mNewG + mH;
|
||||
|
||||
mOpen.Push(mNewLocation);
|
||||
mCalcGrid[mNewLocation].Status = mOpenNodeValue;
|
||||
}
|
||||
mCalcGrid[mLocation].Status = mCloseNodeValue;
|
||||
}
|
||||
|
||||
if (mFound)
|
||||
{
|
||||
mClose.Clear();
|
||||
//int posX = endCell.column;
|
||||
//int posY = endCell.row;
|
||||
int posX = endCell.X;
|
||||
int posY = endCell.Y;
|
||||
|
||||
//PathFinderNodeFast fNodeTmp = mCalcGrid[(endCell.row << mGridYLog2) + endCell.column];
|
||||
PathFinderNodeFast fNodeTmp = mCalcGrid[(endCell.Y << mGridYLog2) + endCell.X];
|
||||
totalCost = fNodeTmp.G;
|
||||
PathFinderNode fNode;
|
||||
fNode.F = fNodeTmp.F;
|
||||
fNode.G = fNodeTmp.G;
|
||||
fNode.H = 0;
|
||||
fNode.PX = fNodeTmp.PX;
|
||||
fNode.PY = fNodeTmp.PY;
|
||||
//fNode.X = endCell.column;
|
||||
//fNode.Y = endCell.row;
|
||||
fNode.X = endCell.X;
|
||||
fNode.Y = endCell.Y;
|
||||
|
||||
while (fNode.X != fNode.PX || fNode.Y != fNode.PY)
|
||||
{
|
||||
mClose.Add(fNode);
|
||||
posX = fNode.PX;
|
||||
posY = fNode.PY;
|
||||
fNodeTmp = mCalcGrid[(posY << mGridYLog2) + posX];
|
||||
fNode.F = fNodeTmp.F;
|
||||
fNode.G = fNodeTmp.G;
|
||||
fNode.H = 0;
|
||||
fNode.PX = fNodeTmp.PX;
|
||||
fNode.PY = fNodeTmp.PY;
|
||||
fNode.X = posX;
|
||||
fNode.Y = posY;
|
||||
}
|
||||
return mClose;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
internal class ComparePFNodeMatrix : IComparer<int>
|
||||
{
|
||||
protected PathFinderNodeFast[] mMatrix;
|
||||
|
||||
public ComparePFNodeMatrix(PathFinderNodeFast[] matrix)
|
||||
{
|
||||
mMatrix = matrix;
|
||||
}
|
||||
|
||||
public int Compare(int a, int b)
|
||||
{
|
||||
if (mMatrix[a].F > mMatrix[b].F)
|
||||
return 1;
|
||||
else if (mMatrix[a].F < mMatrix[b].F)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetMatrix(PathFinderNodeFast[] matrix)
|
||||
{
|
||||
mMatrix = matrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/PathFinderFast.cs.meta
Normal file
11
Assets/Scripts/PathFinding/PathFinderFast.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c113766aa9ebd749a3c46a29f64eadd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
442
Assets/Scripts/PathFinding/PathFinderFastNonSQR.cs
Normal file
442
Assets/Scripts/PathFinding/PathFinderFastNonSQR.cs
Normal file
@@ -0,0 +1,442 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using static HxGame.PathFinding.PathFinderFast;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
public class PathFinderFastNonSQR : IPathFinder
|
||||
{
|
||||
private CellNode[] mGrid = null;
|
||||
private PriorityQueueB<int> mOpen = null;
|
||||
private List<PathFinderNode> mClose = new List<PathFinderNode>();
|
||||
private HeuristicFormula mFormula = HeuristicFormula.Manhattan;
|
||||
private bool mDiagonals = true;
|
||||
private bool mHexagonalGrid = false;
|
||||
private float mHEstimate = 1;
|
||||
private float mHeavyDiagonalsCost = 1.4f;
|
||||
private int mMaxSteps = 2000;
|
||||
private float mMaxSearchCost = 100000;
|
||||
private PathFinderNodeFast[] mCalcGrid = null;
|
||||
private byte mOpenNodeValue = 1;
|
||||
private byte mCloseNodeValue = 2;
|
||||
private OnCellCross mOnCellCross = null;
|
||||
|
||||
private float mH = 0;
|
||||
private int mLocation = 0;
|
||||
private int mNewLocation = 0;
|
||||
private ushort mLocationX = 0;
|
||||
private ushort mLocationY = 0;
|
||||
private ushort mNewLocationX = 0;
|
||||
private ushort mNewLocationY = 0;
|
||||
private ushort mGridX = 0;
|
||||
private ushort mGridY = 0;
|
||||
private bool mFound = false;
|
||||
|
||||
private sbyte[,] mDirection = new sbyte[8, 2]
|
||||
{
|
||||
{ 0, -1}, //bottom
|
||||
{ 1, 0}, //right
|
||||
{ 0, 1}, //top
|
||||
{ -1, 0}, //left
|
||||
{ 1, -1}, //right-bottom
|
||||
{ 1, 1}, //right-top
|
||||
{ -1, 1}, //left-top
|
||||
{ -1, -1}, //left-bottom
|
||||
};
|
||||
private readonly sbyte[,] mDirectionHex0 = new sbyte[6, 2]
|
||||
{
|
||||
{ 0, -1 }, //top
|
||||
{ 1, 0 }, //right
|
||||
{ 0, 1 }, //bottom
|
||||
{ -1, 0 }, //left
|
||||
{ 1, 1}, //right-bottom
|
||||
{ -1,1 } //left-bottom
|
||||
};
|
||||
private readonly sbyte[,] mDirectionHex1 = new sbyte[6, 2]
|
||||
{
|
||||
{ 0, -1 }, //top
|
||||
{ 1, 0 }, //right
|
||||
{ 0, 1 }, //bottom
|
||||
{ -1, 0 }, //left
|
||||
{ -1, -1 }, //left-top
|
||||
{ 1, -1} //right-top
|
||||
};
|
||||
private readonly int[] mCellSide0 = new int[6] {
|
||||
(int)CELL_SIDE.Bottom,
|
||||
(int)CELL_SIDE.BottomRight,
|
||||
(int)CELL_SIDE.Top,
|
||||
(int)CELL_SIDE.BottomLeft,
|
||||
(int)CELL_SIDE.TopRight,
|
||||
(int)CELL_SIDE.TopLeft
|
||||
};
|
||||
private readonly int[] mCellSide1 = new int[6] {
|
||||
(int)CELL_SIDE.Bottom,
|
||||
(int)CELL_SIDE.TopRight,
|
||||
(int)CELL_SIDE.Top,
|
||||
(int)CELL_SIDE.TopLeft,
|
||||
(int)CELL_SIDE.BottomLeft,
|
||||
(int)CELL_SIDE.BottomRight
|
||||
};
|
||||
private readonly int[] mCellBoxSides = new int[8] {
|
||||
(int)CELL_SIDE.Bottom,
|
||||
(int)CELL_SIDE.Right,
|
||||
(int)CELL_SIDE.Top,
|
||||
(int)CELL_SIDE.Left,
|
||||
(int)CELL_SIDE.BottomRight,
|
||||
(int)CELL_SIDE.TopRight,
|
||||
(int)CELL_SIDE.TopLeft,
|
||||
(int)CELL_SIDE.BottomLeft
|
||||
};
|
||||
private int mEndLocation = 0;
|
||||
private float mNewG = 0;
|
||||
private int mCellGroupMask = -1;
|
||||
private bool mIgnoreCanCrossCheck;
|
||||
private bool mIgnoreCellCost;
|
||||
private bool mIncludeInvisibleCells;
|
||||
|
||||
public void SetCalcMatrix(CellNode[] grid)
|
||||
{
|
||||
if (grid == null)
|
||||
throw new Exception("Grid cannot be null");
|
||||
if (grid.Length != mGrid.Length) // mGridX != (ushort) (mGrid.GetUpperBound(0) + 1) || mGridY != (ushort) (mGrid.GetUpperBound(1) + 1))
|
||||
throw new Exception("SetCalcMatrix called with matrix with different dimensions. Call constructor instead.");
|
||||
mGrid = grid;
|
||||
|
||||
Array.Clear(mCalcGrid, 0, mCalcGrid.Length);
|
||||
ComparePFNodeMatrix comparer = (ComparePFNodeMatrix)mOpen.comparer;
|
||||
comparer.SetMatrix(mCalcGrid);
|
||||
}
|
||||
|
||||
public HeuristicFormula Formula
|
||||
{
|
||||
get { return mFormula; }
|
||||
set { mFormula = value; }
|
||||
}
|
||||
public bool Diagonals
|
||||
{
|
||||
get { return mDiagonals; }
|
||||
set
|
||||
{
|
||||
mDiagonals = value;
|
||||
if (mDiagonals)
|
||||
mDirection = new sbyte[8, 2] {
|
||||
{ 0, -1 },
|
||||
{ 1, 0 },
|
||||
{ 0, 1 },
|
||||
{ -1, 0 },
|
||||
{ 1, -1 },
|
||||
{ 1, 1 },
|
||||
{ -1, 1 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
else
|
||||
mDirection = new sbyte[4, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
|
||||
}
|
||||
}
|
||||
|
||||
public float HeavyDiagonalsCost
|
||||
{
|
||||
get { return mHeavyDiagonalsCost; }
|
||||
set { mHeavyDiagonalsCost = value; }
|
||||
}
|
||||
|
||||
public bool HexagonalGrid
|
||||
{
|
||||
get { return mHexagonalGrid; }
|
||||
set { mHexagonalGrid = value; }
|
||||
}
|
||||
|
||||
public float HeuristicEstimate
|
||||
{
|
||||
get { return mHEstimate; }
|
||||
set { mHEstimate = value; }
|
||||
}
|
||||
|
||||
public float MaxSearchCost
|
||||
{
|
||||
get { return mMaxSearchCost; }
|
||||
set { mMaxSearchCost = value; }
|
||||
}
|
||||
|
||||
public int MaxSteps
|
||||
{
|
||||
get { return mMaxSteps; }
|
||||
set { mMaxSteps = value; }
|
||||
}
|
||||
|
||||
|
||||
public OnCellCross OnCellCross
|
||||
{
|
||||
get { return mOnCellCross; }
|
||||
set { mOnCellCross = value; }
|
||||
}
|
||||
|
||||
public int CellGroupMask
|
||||
{
|
||||
get { return mCellGroupMask; }
|
||||
set { mCellGroupMask = value; }
|
||||
}
|
||||
|
||||
public bool IgnoreCanCrossCheck
|
||||
{
|
||||
get { return mIgnoreCanCrossCheck; }
|
||||
set { mIgnoreCanCrossCheck = value; }
|
||||
}
|
||||
|
||||
public bool IgnoreCellCost
|
||||
{
|
||||
get { return mIgnoreCellCost; }
|
||||
set { mIgnoreCellCost = value; }
|
||||
}
|
||||
|
||||
public bool IncludeInvisibleCells
|
||||
{
|
||||
get { return mIncludeInvisibleCells; }
|
||||
set { mIncludeInvisibleCells = value; }
|
||||
}
|
||||
|
||||
public PathFinderFastNonSQR(CellNode[] grid, int gridWidth, int gridHeight)
|
||||
{
|
||||
if (grid == null)
|
||||
throw new Exception("Grid cannot be null");
|
||||
|
||||
mGrid = grid;
|
||||
mGridX = (ushort)gridWidth;
|
||||
mGridY = (ushort)gridHeight;
|
||||
|
||||
if (mCalcGrid == null || mCalcGrid.Length != (mGridX * mGridY))
|
||||
mCalcGrid = new PathFinderNodeFast[mGridX * mGridY];
|
||||
|
||||
mOpen = new PriorityQueueB<int>(new ComparePFNodeMatrix(mCalcGrid));
|
||||
}
|
||||
|
||||
public List<PathFinderNode> FindPath(CellNode startCell, CellNode endCell, out float totalCost, bool evenLayout)
|
||||
{
|
||||
PathFindingPoint start = new PathFindingPoint(startCell.X, startCell.Y);
|
||||
PathFindingPoint end = new PathFindingPoint(endCell.X, endCell.Y);
|
||||
|
||||
totalCost = 0;
|
||||
mFound = false;
|
||||
int evenLayoutValue = evenLayout ? 1 : 0;
|
||||
if (mOpenNodeValue > 250)
|
||||
{
|
||||
Array.Clear(mCalcGrid, 0, mCalcGrid.Length);
|
||||
mOpenNodeValue = 1;
|
||||
mCloseNodeValue = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mOpenNodeValue += 2;
|
||||
mCloseNodeValue += 2;
|
||||
}
|
||||
mOpen.Clear();
|
||||
mClose.Clear();
|
||||
int maxi;
|
||||
if (mHexagonalGrid)
|
||||
maxi = 6;
|
||||
else
|
||||
maxi = mDiagonals ? 8 : 4;
|
||||
|
||||
mLocation = (start.y * mGridX) + start.x;
|
||||
mEndLocation = (end.y * mGridX) + end.x;
|
||||
mCalcGrid[mLocation].G = 0;
|
||||
mCalcGrid[mLocation].F = mHEstimate;
|
||||
mCalcGrid[mLocation].PX = (ushort)start.x;
|
||||
mCalcGrid[mLocation].PY = (ushort)start.y;
|
||||
mCalcGrid[mLocation].Status = mOpenNodeValue;
|
||||
mCalcGrid[mLocation].Steps = 0;
|
||||
|
||||
mOpen.Push(mLocation);
|
||||
while (mOpen.Count > 0)
|
||||
{
|
||||
mLocation = mOpen.Pop();
|
||||
|
||||
if (mCalcGrid[mLocation].Status == mCloseNodeValue)
|
||||
continue;
|
||||
|
||||
if (mLocation == mEndLocation)
|
||||
{
|
||||
mCalcGrid[mLocation].Status = mCloseNodeValue;
|
||||
mFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
mLocationX = (ushort)(mLocation % mGridX);
|
||||
mLocationY = (ushort)(mLocation / mGridX);
|
||||
|
||||
bool hasSideCosts = false;
|
||||
float[] sideCosts = mGrid[mLocation].crossCost;
|
||||
if (!mIgnoreCellCost && sideCosts != null)
|
||||
hasSideCosts = true;
|
||||
|
||||
for (int i = 0; i < maxi; i++)
|
||||
{
|
||||
int cellSide;
|
||||
if (mHexagonalGrid)
|
||||
{
|
||||
if (mLocationX % 2 == evenLayoutValue)
|
||||
{
|
||||
mNewLocationX = (ushort)(mLocationX + mDirectionHex0[i, 0]);
|
||||
mNewLocationY = (ushort)(mLocationY + mDirectionHex0[i, 1]);
|
||||
cellSide = mCellSide0[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
mNewLocationX = (ushort)(mLocationX + mDirectionHex1[i, 0]);
|
||||
mNewLocationY = (ushort)(mLocationY + mDirectionHex1[i, 1]);
|
||||
cellSide = mCellSide1[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mNewLocationX = (ushort)(mLocationX + mDirection[i, 0]);
|
||||
mNewLocationY = (ushort)(mLocationY + mDirection[i, 1]);
|
||||
cellSide = mCellBoxSides[i];
|
||||
}
|
||||
|
||||
if (mNewLocationY >= mGridY)
|
||||
continue;
|
||||
|
||||
if (mNewLocationX >= mGridX)
|
||||
continue;
|
||||
|
||||
mNewLocation = (mNewLocationY * mGridX) + mNewLocationX;
|
||||
if (mGrid[mNewLocation].cellType == MapManager.CellType.Obstacle && !mIgnoreCanCrossCheck)
|
||||
{
|
||||
Debug.Log($"{mNewLocation}<7D><><EFBFBD>赲<EFBFBD><E8B5B2>");
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (!mIncludeInvisibleCells && !mGrid[mNewLocation].visible)
|
||||
// continue;
|
||||
float gridValue = (mGrid[mNewLocation].group & mCellGroupMask) != 0 ? 1 : 0;
|
||||
if (gridValue == 0)
|
||||
continue;
|
||||
|
||||
if (hasSideCosts)
|
||||
{
|
||||
gridValue = sideCosts[cellSide];
|
||||
if (gridValue <= 0)
|
||||
gridValue = 1;
|
||||
}
|
||||
if (mOnCellCross != null)
|
||||
{
|
||||
gridValue += mOnCellCross(mNewLocation);
|
||||
}
|
||||
|
||||
if (!mHexagonalGrid && i > 3)
|
||||
mNewG = mCalcGrid[mLocation].G + gridValue * mHeavyDiagonalsCost;
|
||||
else
|
||||
mNewG = mCalcGrid[mLocation].G + gridValue;
|
||||
|
||||
if (mNewG > mMaxSearchCost || mCalcGrid[mLocation].Steps >= mMaxSteps)
|
||||
continue;
|
||||
|
||||
if (mCalcGrid[mNewLocation].Status == mOpenNodeValue || mCalcGrid[mNewLocation].Status == mCloseNodeValue)
|
||||
{
|
||||
if (mCalcGrid[mNewLocation].G <= mNewG)
|
||||
continue;
|
||||
}
|
||||
|
||||
mCalcGrid[mNewLocation].PX = mLocationX;
|
||||
mCalcGrid[mNewLocation].PY = mLocationY;
|
||||
mCalcGrid[mNewLocation].G = mNewG;
|
||||
mCalcGrid[mNewLocation].Steps = mCalcGrid[mLocation].Steps + 1;
|
||||
|
||||
int dist = Math.Abs(mNewLocationX - end.x);
|
||||
switch (mFormula)
|
||||
{
|
||||
default:
|
||||
case HeuristicFormula.Manhattan:
|
||||
mH = mHEstimate * (dist + Math.Abs(mNewLocationY - end.y));
|
||||
break;
|
||||
case HeuristicFormula.MaxDXDY:
|
||||
mH = mHEstimate * (Math.Max(dist, Math.Abs(mNewLocationY - end.y)));
|
||||
break;
|
||||
case HeuristicFormula.DiagonalShortCut:
|
||||
int h_diagonal = Math.Min(dist, Math.Abs(mNewLocationY - end.y));
|
||||
int h_straight = (dist + Math.Abs(mNewLocationY - end.y));
|
||||
mH = (mHEstimate * 2) * h_diagonal + mHEstimate * (h_straight - 2 * h_diagonal);
|
||||
break;
|
||||
case HeuristicFormula.Euclidean:
|
||||
mH = mHEstimate * (float)(Math.Sqrt(Math.Pow(dist, 2) + Math.Pow((mNewLocationY - end.y), 2)));
|
||||
break;
|
||||
case HeuristicFormula.EuclideanNoSQR:
|
||||
mH = mHEstimate * (float)(Math.Pow(dist, 2) + Math.Pow((mNewLocationY - end.y), 2));
|
||||
break;
|
||||
case HeuristicFormula.Custom1:
|
||||
PathFindingPoint dxy = new PathFindingPoint(dist, Math.Abs(end.y - mNewLocationY));
|
||||
float Orthogonal = Math.Abs(dxy.x - dxy.y);
|
||||
float Diagonal = Math.Abs(((dxy.x + dxy.y) - Orthogonal) / 2);
|
||||
mH = mHEstimate * (Diagonal + Orthogonal + dxy.x + dxy.y);
|
||||
break;
|
||||
}
|
||||
mCalcGrid[mNewLocation].F = mNewG + mH;
|
||||
|
||||
mOpen.Push(mNewLocation);
|
||||
mCalcGrid[mNewLocation].Status = mOpenNodeValue;
|
||||
}
|
||||
mCalcGrid[mLocation].Status = mCloseNodeValue;
|
||||
}
|
||||
if (mFound)
|
||||
{
|
||||
mClose.Clear();
|
||||
|
||||
PathFinderNodeFast fNodeTmp = mCalcGrid[(end.y * mGridX) + end.x];
|
||||
totalCost = fNodeTmp.G;
|
||||
PathFinderNode fNode;
|
||||
fNode.F = fNodeTmp.F;
|
||||
fNode.G = fNodeTmp.G;
|
||||
fNode.H = 0;
|
||||
fNode.PX = fNodeTmp.PX;
|
||||
fNode.PY = fNodeTmp.PY;
|
||||
fNode.X = end.x;
|
||||
fNode.Y = end.y;
|
||||
|
||||
while (fNode.X != fNode.PX || fNode.Y != fNode.PY)
|
||||
{
|
||||
mClose.Add(fNode);
|
||||
int posX = fNode.PX;
|
||||
int posY = fNode.PY;
|
||||
fNodeTmp = mCalcGrid[(posY * mGridX) + posX];
|
||||
fNode.F = fNodeTmp.F;
|
||||
fNode.G = fNodeTmp.G;
|
||||
fNode.H = 0;
|
||||
fNode.PX = fNodeTmp.PX;
|
||||
fNode.PY = fNodeTmp.PY;
|
||||
fNode.X = posX;
|
||||
fNode.Y = posY;
|
||||
}
|
||||
|
||||
return mClose;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal class ComparePFNodeMatrix : IComparer<int>
|
||||
{
|
||||
protected PathFinderNodeFast[] mMatrix;
|
||||
|
||||
public ComparePFNodeMatrix(PathFinderNodeFast[] matrix)
|
||||
{
|
||||
mMatrix = matrix;
|
||||
}
|
||||
|
||||
public int Compare(int a, int b)
|
||||
{
|
||||
if (mMatrix[a].F > mMatrix[b].F)
|
||||
return 1;
|
||||
else if (mMatrix[a].F < mMatrix[b].F)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetMatrix(PathFinderNodeFast[] matrix)
|
||||
{
|
||||
mMatrix = matrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/PathFinderFastNonSQR.cs.meta
Normal file
11
Assets/Scripts/PathFinding/PathFinderFastNonSQR.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1fec4aae92683f469460bfddb57634a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
95
Assets/Scripts/PathFinding/PathFinderHelper.cs
Normal file
95
Assets/Scripts/PathFinding/PathFinderHelper.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
public class PathFinderHelper
|
||||
{
|
||||
public delegate int PathFindingEvent(int cellIndex);
|
||||
public event PathFindingEvent OnPathFindingCrossCell;
|
||||
|
||||
int _pathFindingMaxSteps = 2000;
|
||||
int _pathFindingMaxCost = 2000;
|
||||
bool _pathFindingUseDiagonals = true;
|
||||
float _pathFindingHeavyDiagonalsCost = 1.4f;
|
||||
CellNode[] cellsNode = null;
|
||||
|
||||
int _cellRows;
|
||||
int _cellCols;
|
||||
IPathFinder finder = null;
|
||||
|
||||
public PathFinderHelper(CellNode[] cellsNode, int rows, int cols)
|
||||
{
|
||||
this.cellsNode = cellsNode;
|
||||
if (finder == null)
|
||||
{
|
||||
if ((cols & (cols - 1)) == 0)
|
||||
finder = new PathFinderFast(cellsNode, cols, rows);
|
||||
else
|
||||
finder = new PathFinderFastNonSQR(cellsNode, cols, rows);
|
||||
}
|
||||
|
||||
_cellRows = rows;
|
||||
_cellCols = cols;
|
||||
}
|
||||
|
||||
public List<int> FindPath(int cellIndexStart, int cellIndexEnd, float maxSearchCost = 0, int maxSteps = 0, int cellGroupMask = -1)
|
||||
{
|
||||
float dummy;
|
||||
return FindPath(cellIndexStart, cellIndexEnd, out dummy, maxSearchCost, maxSteps, cellGroupMask);
|
||||
}
|
||||
|
||||
public List<int> FindPath(int cellIndexStart, int cellIndexEnd, out float totalCost, float maxSearchCost = 0, int maxSteps = 0, int cellGroupMask = -1)
|
||||
{
|
||||
List<int> results = new List<int>();
|
||||
FindPath(cellIndexStart, cellIndexEnd, results, out totalCost, maxSearchCost, maxSteps, cellGroupMask);
|
||||
return results;
|
||||
}
|
||||
|
||||
public int FindPath(int cellIndexStart, int cellIndexEnd, List<int> cellIndices, out float totalCost, float maxSearchCost = 0, int maxSteps = 0, int cellGroupMask = -1)
|
||||
{
|
||||
finder.Formula = HeuristicFormula.MaxDXDY;
|
||||
finder.MaxSteps = maxSteps > 0 ? maxSteps : _pathFindingMaxSteps;
|
||||
finder.Diagonals = _pathFindingUseDiagonals;
|
||||
finder.HeavyDiagonalsCost = _pathFindingHeavyDiagonalsCost;
|
||||
finder.HexagonalGrid = false;
|
||||
finder.MaxSearchCost = maxSearchCost > 0 ? maxSearchCost : _pathFindingMaxCost;
|
||||
finder.CellGroupMask = cellGroupMask;
|
||||
finder.IgnoreCanCrossCheck = false;
|
||||
finder.IgnoreCellCost = false;
|
||||
if (OnPathFindingCrossCell != null)
|
||||
finder.OnCellCross = FindRoutePositionValidator;
|
||||
else
|
||||
finder.OnCellCross = null;
|
||||
|
||||
CellNode startCell = cellsNode[cellIndexStart];
|
||||
CellNode endCell = cellsNode[cellIndexEnd];
|
||||
List<PathFinderNode> route = finder.FindPath(startCell, endCell, out totalCost, false);
|
||||
if (route != null)
|
||||
{
|
||||
int routeCount = route.Count;
|
||||
for (int r = routeCount - 2; r >= 0; r--)
|
||||
{
|
||||
int cellIndex = route[r].PY * _cellCols + route[r].PX;
|
||||
cellIndices.Add(cellIndex);
|
||||
}
|
||||
|
||||
return route.Count;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
private float FindRoutePositionValidator(int cellIndex)
|
||||
{
|
||||
float cost = 1;
|
||||
if (OnPathFindingCrossCell != null)
|
||||
{
|
||||
cost = OnPathFindingCrossCell(cellIndex);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/PathFinderHelper.cs.meta
Normal file
11
Assets/Scripts/PathFinding/PathFinderHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6373f2659a17e14a945b23e986fcea5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Assets/Scripts/PathFinding/PathFindingPoint.cs
Normal file
29
Assets/Scripts/PathFinding/PathFindingPoint.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
public class PathFindingPoint
|
||||
{
|
||||
private int _x;
|
||||
private int _y;
|
||||
|
||||
public PathFindingPoint(int x, int y)
|
||||
{
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
|
||||
public int x { get { return this._x; } set { this._x = value; } }
|
||||
|
||||
public int y { get { return this._y; } set { this._y = value; } }
|
||||
|
||||
// For debugging
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}, {1}", this.x, this.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/PathFindingPoint.cs.meta
Normal file
11
Assets/Scripts/PathFinding/PathFindingPoint.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8a181cfe2076a74baa47955135d22b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
231
Assets/Scripts/PathFinding/PriorityQueueB.cs
Normal file
231
Assets/Scripts/PathFinding/PriorityQueueB.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HxGame.PathFinding
|
||||
{
|
||||
public interface IPriorityQueue<T>
|
||||
{
|
||||
int Push(T item);
|
||||
|
||||
T Pop();
|
||||
|
||||
T Peek();
|
||||
|
||||
void Update(int i);
|
||||
}
|
||||
|
||||
public class PriorityQueueB<T> : IPriorityQueue<T>
|
||||
{
|
||||
protected T[] InnerList;
|
||||
protected IComparer<T> mComparer;
|
||||
protected int InnerListCount;
|
||||
|
||||
public PriorityQueueB()
|
||||
{
|
||||
mComparer = Comparer<T>.Default;
|
||||
InnerList = new T[4096];
|
||||
InnerListCount = 0;
|
||||
}
|
||||
|
||||
public PriorityQueueB(IComparer<T> comparer)
|
||||
{
|
||||
mComparer = comparer;
|
||||
InnerList = new T[4096];
|
||||
InnerListCount = 0;
|
||||
}
|
||||
|
||||
public IComparer<T> comparer { get { return mComparer; } }
|
||||
|
||||
|
||||
protected void SwapElements(int i, int j)
|
||||
{
|
||||
T h = InnerList[i];
|
||||
InnerList[i] = InnerList[j];
|
||||
InnerList[j] = h;
|
||||
}
|
||||
|
||||
protected virtual int OnCompare(int i, int j)
|
||||
{
|
||||
return mComparer.Compare(InnerList[i], InnerList[j]);
|
||||
}
|
||||
|
||||
|
||||
// <returns><3E>б<EFBFBD><D0B1>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD></returns>
|
||||
public int Push(T item)
|
||||
{
|
||||
int p = InnerListCount, p2;
|
||||
if (InnerListCount >= InnerList.Length)
|
||||
{
|
||||
ResizeInnerList();
|
||||
}
|
||||
InnerList[InnerListCount++] = item;
|
||||
do
|
||||
{
|
||||
if (p == 0)
|
||||
break;
|
||||
p2 = (p - 1) / 2;
|
||||
T InnerListp = InnerList[p];
|
||||
T InnerListp2 = InnerList[p2];
|
||||
if (mComparer.Compare(InnerListp, InnerListp2) < 0)
|
||||
{
|
||||
// Swap
|
||||
InnerList[p] = InnerListp2;
|
||||
InnerList[p2] = InnerListp;
|
||||
p = p2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while (true);
|
||||
return p;
|
||||
}
|
||||
|
||||
void ResizeInnerList()
|
||||
{
|
||||
T[] newInnerList = new T[InnerListCount * 2];
|
||||
Array.Copy(InnerList, newInnerList, InnerListCount);
|
||||
InnerList = newInnerList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><>ȡ<EFBFBD><C8A1>С<EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T Pop()
|
||||
{
|
||||
T result = InnerList[0];
|
||||
int p = 0, p1, p2, pn;
|
||||
int count = InnerListCount - 1;
|
||||
InnerList[0] = InnerList[count]; // InnerList.Count - 1
|
||||
InnerListCount--;
|
||||
do
|
||||
{
|
||||
pn = p;
|
||||
p1 = 2 * p + 1;
|
||||
p2 = p1 + 1; //2 * p + 2;
|
||||
|
||||
if (count > p1)
|
||||
{
|
||||
if (mComparer.Compare(InnerList[p], InnerList[p1]) > 0)
|
||||
{
|
||||
p = p1;
|
||||
}
|
||||
}
|
||||
if (count > p2)
|
||||
{
|
||||
if (mComparer.Compare(InnerList[p], InnerList[p2]) > 0)
|
||||
{
|
||||
p = p2;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == pn)
|
||||
break;
|
||||
|
||||
// Swap
|
||||
T h = InnerList[p];
|
||||
InnerList[p] = InnerList[pn];
|
||||
InnerList[pn] = h;
|
||||
|
||||
} while (true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ֪ͨ<CDA8><D6AA><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>i<EFBFBD><69><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD>Ѹ<EFBFBD><D1B8><EFBFBD>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// <20><>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><CEBA><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>ʽIList.this)
|
||||
/// <20><><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>ڲ<EFBFBD>ȷ<EFBFBD><C8B7>֪<EFBFBD><D6AA><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD>ʲô<CAB2><C3B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5>ô˺<C3B4><CBBA><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="i"><3E><><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
public void Update(int i)
|
||||
{
|
||||
int p = i, pn;
|
||||
int p1, p2;
|
||||
do
|
||||
{ // aufsteigen
|
||||
if (p == 0)
|
||||
break;
|
||||
p2 = (p - 1) / 2;
|
||||
if (OnCompare(p, p2) < 0)
|
||||
{
|
||||
SwapElements(p, p2);
|
||||
p = p2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while (true);
|
||||
if (p < i)
|
||||
return;
|
||||
do
|
||||
{ // absteigen
|
||||
pn = p;
|
||||
p1 = 2 * p + 1;
|
||||
p2 = 2 * p + 2;
|
||||
if (InnerListCount > p1 && OnCompare(p, p1) > 0) // links kleiner
|
||||
p = p1;
|
||||
if (InnerListCount > p2 && OnCompare(p, p2) > 0) // rechts noch kleiner
|
||||
p = p2;
|
||||
|
||||
if (p == pn)
|
||||
break;
|
||||
SwapElements(p, pn);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20>ڲ<EFBFBD><DAB2>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>»<EFBFBD>ȡ<EFBFBD><C8A1>С<EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD>
|
||||
/// </summary>
|
||||
/// <returns><3E><>С<EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD></returns>
|
||||
public T Peek()
|
||||
{
|
||||
if (InnerListCount > 0)
|
||||
return InnerList[0];
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
InnerListCount = 0; //.Clear ();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return InnerListCount; }
|
||||
}
|
||||
|
||||
public void RemoveLocation(T item)
|
||||
{
|
||||
int index = -1;
|
||||
for (int i = 0; i < InnerListCount; i++)
|
||||
{
|
||||
if (mComparer.Compare(InnerList[i], item) == 0)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
//InnerList.RemoveAt (index);
|
||||
for (int i = index; i < InnerListCount - 1; i++)
|
||||
{
|
||||
InnerList[i] = InnerList[i + 1];
|
||||
}
|
||||
InnerListCount--;
|
||||
}
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get { return InnerList[index]; }
|
||||
set
|
||||
{
|
||||
InnerList[index] = value;
|
||||
Update(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Scripts/PathFinding/PriorityQueueB.cs.meta
Normal file
11
Assets/Scripts/PathFinding/PriorityQueueB.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edcc7235ab5fad649ac32e2c1aef48f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user