no message

This commit is contained in:
PC-20230316NUNE\Administrator
2024-02-20 18:39:12 +08:00
parent 97b3671979
commit 2b467e56ad
1876 changed files with 440340 additions and 35266 deletions

View File

@@ -0,0 +1,294 @@
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using HPJ.Simulation.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace HPJ.Simulation.Pathing
{
public class AStar : PathingCalculation
{
public static AStar Instance = null;
public override void Initialize()
{
NavigationType = Enums.NavigationTypes.AStar;
if (!PathingTypes.ContainsKey(NavigationType))
{
PathingTypes.Add(NavigationType, this);
}
}
public override void CalculatePath(NavigationPath Path, Map.Map OccuringMap, out string Status, out bool Succeeded)
{
try
{
List<IntVector2> OpenList = new List<IntVector2>();
HashSet<IntVector2> ClosedList = new HashSet<IntVector2>();
Dictionary<IntVector2, AStarTileData> SortedList = new Dictionary<IntVector2, AStarTileData>();
IntVector2 StartTile = Path.Info.PointA;
IntVector2 EndTile = Path.Info.PointB;
OpenList.Add(StartTile);
AStarTileData StartingTileData = new AStarTileData(new IntVector2(-1, -1), CalculateDistanceCost(StartTile.x, StartTile.y, EndTile.x, EndTile.y));
StartingTileData.GCost = 0;
StartingTileData.FCost = StartingTileData.GCost + StartingTileData.HCost;
SortedList.Add(StartTile, StartingTileData);
int TentativeGCost = 0;
IntVector2 CurrentTile = StartTile;
int Iterations = 0;
bool MaxIterationsMade = false;
int MaxIterations = 3000;
// Get BitMap
BytePointMap BitMap = Path.HostMap.GetBytePointMap(Path);
TileTypes[] PrefferedTiles = Path.Info.PrefferedTilesKey.StringToTilesArray();
while (OpenList.Count > 0)
{
// Give a safty range of 2 times the range in terms of iterations, if it cannot find a path by then, it's failed. can probably cannot be reached
if (Iterations > MaxIterations)
{
MaxIterationsMade = true;
break;
}
Iterations++;
int CurrentNodeIndex = GetLowestFCostTileIndex(OpenList, Path.HostMap, StartTile, EndTile, CurrentTile, PrefferedTiles);
CurrentTile = OpenList[CurrentNodeIndex];
if (EndTile == CurrentTile)
{
// Reached the end
//Debug.Log("Found the End - Should be Path Complete");
break;
}
// Remove current
OpenList.RemoveAt(CurrentNodeIndex);
ClosedList.Add(CurrentTile);
AStarTileData CurrentData = SortedList[CurrentTile];
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0)
{
continue;
}
IntVector2 neighbourPosition = new IntVector2(CurrentTile.x + x, CurrentTile.y + y);
if (BitMap.GetTileSpeed(neighbourPosition.x, neighbourPosition.y) == 0)
{
continue;
}
if (ClosedList.Contains(neighbourPosition))
{
continue;
}
// Get Corner Types, if its a wall, continue (DO NOT WALK THROUGH WALLS)
if (!BitMap.CornerCutting)
{
if (x != 0 && y != 0)
{
IntVector2 cornerAdjacentPosition = new IntVector2(CurrentTile.x + x, CurrentTile.y);
if (BitMap.Tiles[cornerAdjacentPosition.x, cornerAdjacentPosition.y] == 0)
{
continue;
}
cornerAdjacentPosition.x = CurrentTile.x;
cornerAdjacentPosition.y = CurrentTile.y + y;
if (BitMap.Tiles[cornerAdjacentPosition.x, cornerAdjacentPosition.y] == 0)
{
continue;
}
}
}
AStarTileData NeighbourData;
if (!SortedList.TryGetValue(neighbourPosition, out NeighbourData))
{
NeighbourData = new AStarTileData(new IntVector2(-1, -1), CalculateDistanceCost(neighbourPosition.x, neighbourPosition.y, EndTile.x, EndTile.y));
SortedList.Add(neighbourPosition, NeighbourData);
}
TentativeGCost = CurrentData.GCost + CalculateDistanceCost(CurrentTile.x, CurrentTile.y, neighbourPosition.x, neighbourPosition.y);
if (TentativeGCost < NeighbourData.GCost)
{
//Debug.Log("Lower G Cost");
NeighbourData.RouteFromTileIndex = CurrentTile;
NeighbourData.GCost = TentativeGCost;
NeighbourData.FCost = NeighbourData.GCost + NeighbourData.HCost;
SortedList[neighbourPosition] = NeighbourData;
if (!OpenList.Contains(neighbourPosition))
{
//Debug.Log("LEnter To OpenList");
OpenList.Add(neighbourPosition);
}
}
}
}
}
AStarTileData EndTileData;
if (MaxIterationsMade)
{
Succeeded = false;
Status = $"Path is too far away, or cannot be reached --> Iteration Max Reached {MaxIterations}";
}
else if (!SortedList.TryGetValue(EndTile, out EndTileData) || EndTileData.RouteFromTileIndex.x == -1)
{
// No Valid Path Found
Succeeded = false;
Status = "Open list emptied - But did NOT reach the End, Likely Trapped";
}
else
{
Succeeded = true;
// Path should be valid
SortPath(Path, SortedList, EndTile);
Status = $"Found a Valid Path 'Iterations ({Iterations} / {MaxIterations})' -> 'List Counts (Open:{OpenList.Count} / Closed:{ClosedList.Count})'";
}
}
catch (Exception ex)
{
Status = "Faled";
OccuringMap.LogError($"{ex.Message}: {ex.Source}: {ex.StackTrace}");
Succeeded = false;
}
}
protected int GetLowestFCostTileIndex(List<IntVector2> OpenList, Map.Map OccuringMap, IntVector2 Start, IntVector2 End, IntVector2 CurrentTileIndex, TileTypes[] PrefferedTiles)
{
int LowestCostIndex = 0;
if (PrefferedTiles.Contains(OccuringMap.GetTileType(CurrentTileIndex)))
{
// Try to stick to the group tile unless the tile is farther from the start AND closer to the end
int CurrentStartScore = CalculateDistanceCost(CurrentTileIndex.x, CurrentTileIndex.y, Start.x, Start.y);
int CurrentEndScore = CalculateDistanceCost(CurrentTileIndex.x, CurrentTileIndex.y, End.x, End.y);
int LowestSameCostIndex = -1;
TileTypes ZeroTileType = OccuringMap.GetTileType(OpenList[0].x, OpenList[0].y);
byte TileSpeed = OccuringMap.GetTileSpeedData(ZeroTileType);
int ZeroStartScore = CalculateDistanceCost(OpenList[0].x, OpenList[0].y, Start.x, Start.y);
int ZeroEndScore = CalculateDistanceCost(OpenList[0].x, OpenList[0].y, End.x, End.y);
int CurrentLowestCost = ZeroEndScore / TileSpeed;
int CurrentSameLowestCost = int.MaxValue;
if (PrefferedTiles.Contains(ZeroTileType) || (ZeroStartScore > CurrentStartScore && ZeroEndScore < CurrentEndScore))
{
LowestSameCostIndex = 0;
CurrentSameLowestCost = CurrentLowestCost;
}
for (int i = 1; i < OpenList.Count; i++)
{
TileTypes iTileType = OccuringMap.GetTileType(OpenList[i].x, OpenList[i].y);
TileSpeed = OccuringMap.GetTileSpeedData(iTileType);
int iStartScore = CalculateDistanceCost(OpenList[i].x, OpenList[i].y, Start.x, Start.y);
int iEndScore = CalculateDistanceCost(OpenList[i].x, OpenList[i].y, End.x, End.y);
int testCost = iEndScore / TileSpeed;
if (testCost < CurrentLowestCost)
{
CurrentLowestCost = testCost;
LowestCostIndex = i;
}
if (PrefferedTiles.Contains(iTileType) || (iStartScore > CurrentStartScore && iEndScore < CurrentEndScore))
{
if (testCost < CurrentSameLowestCost)
{
LowestSameCostIndex = i;
CurrentSameLowestCost = testCost;
}
}
}
if (LowestSameCostIndex != -1)
{
return LowestSameCostIndex;
}
}
else
{
// Typical AStar pathfinding
int TileSpeed = OccuringMap.GetTileSpeedData(OccuringMap.GetTileType(OpenList[0].x, OpenList[0].y));
int CurrentLowestCost = CalculateDistanceCost(OpenList[0].x, OpenList[0].y, End.x, End.y) / TileSpeed;
for (int i = 1; i < OpenList.Count; i++)
{
TileSpeed = OccuringMap.GetTileSpeedData(OccuringMap.GetTileType(OpenList[i].x, OpenList[i].y));
int testCost = CalculateDistanceCost(OpenList[i].x, OpenList[i].y, End.x, End.y) / TileSpeed;
if (testCost < CurrentLowestCost)
{
CurrentLowestCost = testCost;
LowestCostIndex = i;
}
}
}
return LowestCostIndex;
}
protected int CalculateDistanceCost(int x1, int y1, int x2, int y2)
{
int X_Distance = x1 - x2;
X_Distance = X_Distance < 0 ? -X_Distance : X_Distance;
int Y_Distance = y1 - y2;
Y_Distance = Y_Distance < 0 ? -Y_Distance : Y_Distance;
int remaining = X_Distance - Y_Distance;
remaining = remaining < 0 ? -remaining : remaining;
if (Y_Distance < X_Distance)
{
return 14 * Y_Distance + 10 * remaining;
}
else
{
return 14 * X_Distance + 10 * remaining;
}
}
protected void SortPath(NavigationPath Path, Dictionary<IntVector2, AStarTileData> SortedData, IntVector2 EndTileIndex)
{
AStarTileData CurrentTile = SortedData[EndTileIndex];
int InsertIndex = Path.Path.Count;
Path.Path.Insert(InsertIndex, EndTileIndex);
// The Route From Index of the starting tile should be the only one with a (-1, -1) index
while (CurrentTile.RouteFromTileIndex.x != -1)
{
Path.Path.Insert(InsertIndex, CurrentTile.RouteFromTileIndex);
CurrentTile = SortedData[CurrentTile.RouteFromTileIndex];
}
}
public struct AStarTileData
{
public IntVector2 RouteFromTileIndex;
public int FCost;
public int GCost;
public int HCost;
public AStarTileData(IntVector2 RouteFromTile, int EndCost)
{
RouteFromTileIndex = RouteFromTile;
FCost = int.MaxValue;
GCost = int.MaxValue;
HCost = EndCost;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 183160215d33bde4981db6e6901c2972
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91124dce985e03b428dfcfd28071da97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,340 @@
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using HPJ.Simulation.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
namespace HPJ.Simulation.Pathing
{
/// <summary>
/// The Base class for any pathfinding algorithms
/// </summary>
public abstract class PathingCalculation
{
/// <summary>
/// The Navigation Type this pathing is. Will need to add yours to the enum
/// </summary>
public NavigationTypes NavigationType { get; protected set; }
/// <summary>
/// The Dictionary of all the pathing algorithms
/// </summary>
public static Dictionary<NavigationTypes, PathingCalculation> PathingTypes = new Dictionary<NavigationTypes, PathingCalculation>();
public PathingCalculation()
{
Initialize();
}
/// <summary>
/// Initializes the Algorithm, You will need to call this or add this for your algorithm
/// </summary>
public virtual void Initialize()
{
NavigationType = NavigationTypes.None;
if (!PathingTypes.ContainsKey(NavigationType))
{
PathingTypes.Add(NavigationType, this);
}
}
/// <summary>
/// Calculates the Path for a Navigation Job Request on a specific Map
/// </summary>
/// <param name="Path"></param>
/// <param name="OccuringMap"></param>
/// <param name="Status"></param>
/// <param name="Succeeded"></param>
public abstract void CalculatePath(NavigationPath Path, Map.Map OccuringMap, out string Status, out bool Succeeded);
}
/// <summary>
/// A Navigation Job Request
/// </summary>
[Serializable]
public class NavigationJob
{
#region Navigation Info
/// <summary>
/// Infomation on this Job
/// </summary>
public PathingInfo Info;
/// <summary>
/// Current Step on the Pathfinding Calculation
/// </summary>
public PathfindingCalculationStep CurrentStep;
/// <summary>
/// The Number of tiles away from the start to the end
/// </summary>
public int TilesAway;
/// <summary>
/// Point A of the Path
/// </summary>
public IntVector3 WorldPointA;
/// <summary>
/// Point B of the Path
/// </summary>
public IntVector3 WorldPointB;
/// <summary>
/// If this Job was compatable or not
/// </summary>
public bool Compatable;
/// <summary>
/// Next time this path is pathed, repath it
/// </summary>
public bool RepathSavedPath;
/// <summary>
/// List of Traversable Tiles
/// </summary>
public List<TileTypes> TraverableTileTypes;
/// <summary>
/// List of Prefferred Tiles
/// </summary>
public List<TileTypes> PrefferedTileTypes;
#endregion
#region Navigation Results
/// <summary>
/// The Resulting Path for this Job Request
/// </summary>
public NavigationPath CurrentPath { get; protected set; }
public ushort AgentID { get; set; }
/// <summary>
/// The Callback to the presentation side
/// </summary>
public Action OnCompleteCallback;
#endregion
public NavigationJob(Action onCompleteCallback)
{
Info = new PathingInfo();
CurrentPath = null;
CurrentStep = PathfindingCalculationStep.Incomplete;
OnCompleteCallback = onCompleteCallback;
AgentID = 0;
}
/// <summary>
/// Clears the Job and reverts it back to default
/// </summary>
public void Clear()
{
Info = new PathingInfo();
CurrentPath = null;
CurrentStep = PathfindingCalculationStep.Incomplete;
}
/// <summary>
/// Initializes the Job with the neccessary pathing information
/// </summary>
/// <param name="Start"></param>
/// <param name="End"></param>
/// <param name="TraverableKey"></param>
/// <param name="PrefferedTilesKey"></param>
/// <param name="Navigation"></param>
/// <param name="ForMap"></param>
/// <param name="RepathAnyway"></param>
public void SetDestinationInfo(IntVector3 Start, IntVector3 End, List<TileTypes> TraverableTiles, List<TileTypes> PrefferedTiles, NavigationTypes Navigation, MapSet ForMap, bool RepathAnyway = false)
{
if (Start.x < End.x)
{
WorldPointA = Start;
WorldPointB = End;
}
else if (Start.x > End.x)
{
WorldPointA = End;
WorldPointB = Start;
}
else
{
if (Start.z < End.z)
{
WorldPointA = Start;
WorldPointB = End;
}
else if (Start.z > End.z)
{
WorldPointA = End;
WorldPointB = Start;
}
else
{
WorldPointA = Start;
WorldPointB = End;
}
}
TraverableTileTypes = TraverableTiles;
PrefferedTileTypes = PrefferedTiles;
RepathSavedPath = RepathAnyway;
Info = new PathingInfo(ForMap.GetMapTileIndex(WorldPointA), ForMap.GetMapTileIndex(WorldPointB), Navigation, TraverableTiles.TilesToString(), PrefferedTiles.TilesToString());
TilesAway = JumpPointSearch.Instance.CalculateDistanceCost(Start.x, Start.z, End.x, End.z);
Compatable = ForMap.JobCompatible(this);
}
/// <summary>
/// Sets the resulting path to the request
/// </summary>
/// <param name="path"></param>
internal void SetNewCurrentPath(NavigationPath path)
{
CurrentPath = path;
}
/// <summary>
/// The callback from the simulation when the job request is finished
/// </summary>
internal void PathfindingComplete()
{
CurrentStep = PathfindingCalculationStep.Complete;
OnCompleteCallback?.Invoke();
}
}
/// <summary>
/// The Calculated Path on a specific Map
/// </summary>
[System.Serializable]
public class NavigationPath
{
/// <summary>
/// The map the path was calculated on
/// </summary>
public Map.Map HostMap;
/// <summary>
/// The Information on this Path
/// </summary>
public PathingInfo Info;
/// <summary>
/// The Resulting Path
/// </summary>
public List<IntVector2> Path;
/// <summary>
/// If this Path resulting in a valid path
/// </summary>
public bool ValidPath;
/// <summary>
/// Previous status on the path
/// </summary>
public string PreviousStatus { get; set; }
/// <summary>
/// Asking For Path from specific agent
/// </summary>
public ushort AgentID;
public NavigationPath()
{
Info = new PathingInfo();
Path = new List<IntVector2>();
ValidPath = false;
PreviousStatus = "";
AgentID = 0;
}
public NavigationPath(PathingInfo PathInfo, Map.Map hostMap, ushort ID = 0)
{
Info = PathInfo;
Path = new List<IntVector2>();
ValidPath = false;
HostMap = hostMap;
PreviousStatus = "";
AgentID = 0;
}
/// <summary>
/// Checks to see if your starting point is the first index of the path or the last
/// </summary>
/// <param name="startPoint"></param>
/// <returns></returns>
public bool NeedToReverse(IntVector3 startPoint)
{
if (!ValidPath)
{
return false;
}
if (Path.Count <= 0)
{
return false;
}
return Path[0] != HostMap.GetTileIndexPosition(startPoint);
}
}
/// <summary>
/// The information on a given path
/// </summary>
[System.Serializable]
public struct PathingInfo
{
/// <summary>
/// Point A of a Path
/// </summary>
public IntVector2 PointA;
/// <summary>
/// Point B of a Path
/// </summary>
public IntVector2 PointB;
/// <summary>
/// Navigation type used for this Path
/// </summary>
public NavigationTypes NavigationType;
/// <summary>
/// Traversable Tiles Key
/// </summary>
public string TraversableTilesKey;
/// <summary>
/// Preffered Tile Kep
/// </summary>
public string PrefferedTilesKey;
public PathingInfo(IntVector2 A, IntVector2 B, NavigationTypes Type, string Traverable, string Preffered)
{
// Sort tiles by bottom left so there is no repeats in the saved path Dictionary
if (A.x < B.x)
{
PointA = A;
PointB = B;
}
else if (A.x > B.x)
{
PointA = B;
PointB = A;
}
else
{
if (A.y < B.y)
{
PointA = A;
PointB = B;
}
else if (A.y > B.y)
{
PointA = B;
PointB = A;
}
else
{
PointA = A;
PointB = B;
}
}
NavigationType = Type;
TraversableTilesKey = Traverable;
PrefferedTilesKey = Preffered;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5785cb1e31a25e948b0f11f9b7ae1b5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: