First draft of A* pathfinding implementation

This commit is contained in:
2022-01-16 18:33:43 +01:00
parent fc10cbfc3e
commit 180207f441
5 changed files with 114 additions and 53 deletions

View File

@ -6,7 +6,7 @@
#include "AdventureCameraPawn.h"
#include "AdventureCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "Algo/Reverse.h"
// Sets default values
AAdventureMap::AAdventureMap()
@ -36,17 +36,14 @@ void AAdventureMap::MakeGrid()
{
float XOffset = 0.f;
if (r % 2 != 0)
{
if (r > 1)
{
QOffset--; // The Q axis is (i.e. columns are) oriented diagonally.
}
}
else
if (r % 2 != 0)
{
XOffset = HexWidth / 2;
if (r > 1)
{
QOffset--;
}
}
else { XOffset = HexWidth / 2; }
for (int q = 1; q <= GridSize; q++)
{
@ -86,35 +83,91 @@ int32 AAdventureMap::GridIndex(int32 qAxial, int32 rAxial)
AHexTile* AAdventureMap::RandomHex()
{
int32 RandHex = GridIndex(FMath::RandRange(0, GridSize-1), FMath::RandRange(0, GridSize-1));
//while (RandHex > Grid.Num())
//{
// RandHex = GridIndex(FMath::RandRange(0, GridSize), FMath::RandRange(0, GridSize));
//}
return Grid[RandHex];
}
TArray<AHexTile*> AAdventureMap::Neighbors(AHexTile* OfHex)
{
TArray<AHexTile*> Neighbors;
int32 Index;
int32 I;
Index = GridIndex(OfHex->Q + 1 , OfHex->R + 0 );
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
I = GridIndex(OfHex->Q + 1 , OfHex->R + 0 );
if (Grid.IsValidIndex(I) && OfHex->Distance(Grid[I]) == 1) { Neighbors.Add(Grid[I]); }
Index = GridIndex(OfHex->Q + 1 , OfHex->R - 1 );
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
I = GridIndex(OfHex->Q + 1 , OfHex->R - 1 );
if (Grid.IsValidIndex(I) && OfHex->Distance(Grid[I]) == 1) { Neighbors.Add(Grid[I]); }
Index = GridIndex(OfHex->Q + 0 , OfHex->R - 1 );
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
I = GridIndex(OfHex->Q + 0 , OfHex->R - 1 );
if (Grid.IsValidIndex(I) && OfHex->Distance(Grid[I]) == 1) { Neighbors.Add(Grid[I]); }
Index = GridIndex(OfHex->Q - 1 , OfHex->R + 0 );
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
I = GridIndex(OfHex->Q - 1 , OfHex->R + 0 );
if (Grid.IsValidIndex(I) && OfHex->Distance(Grid[I]) == 1) { Neighbors.Add(Grid[I]); }
Index = GridIndex(OfHex->Q - 1 , OfHex->R + 1 );
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
I = GridIndex(OfHex->Q - 1 , OfHex->R + 1 );
if (Grid.IsValidIndex(I) && OfHex->Distance(Grid[I]) == 1) { Neighbors.Add(Grid[I]); }
Index = GridIndex(OfHex->Q + 0 , OfHex->R + 1 );
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
I = GridIndex(OfHex->Q + 0 , OfHex->R + 1 );
if (Grid.IsValidIndex(I) && OfHex->Distance(Grid[I]) == 1) { Neighbors.Add(Grid[I]); }
return Neighbors;
}
// Be aware that the respective character will become relevant to this function at some point
TArray<AHexTile*> AAdventureMap::FindPathAStar(AHexTile* Start, AHexTile* Goal)
{
TArray<AHexTile*> Priorities;
Priorities.Init(Start, 1);
Goal->CameFrom = Start;
// Editing Hex->CameFrom pointers, i.e. chaining Hexes
while (Priorities.IsValidIndex(0))
{
AHexTile* Current = Priorities[0];
Priorities.RemoveAt(0);
if (*Current == *Goal) { break; }
// Expanding the Frontier
for (AHexTile* Next : Neighbors(Current))
{
int32 NewCost = Current->CostSoFar + Next->MoveCost;
if (!Priorities.Contains(Next) || NewCost < Next->CostSoFar)
{
Next->CostSoFar = NewCost;
int32 NewPrio = NewCost + Next->Distance(Goal);
// Adjust the Priority Queue
if (Priorities.Contains(Next)) { Priorities.Remove(Next); }
for (AHexTile* Hex : Priorities)
{
int32 OldPrio = Hex->CostSoFar + Hex->Distance(Goal);
int32 Index;
Priorities.Find(Hex, Index);
if (OldPrio > NewPrio)
{
Priorities.Insert(Next, Index);
Next->CameFrom = Current;
break;
}
if (Index == Priorities.Num() - 1 && OldPrio <= NewPrio)
{
Priorities.Emplace(Next);
Next->CameFrom = Current;
}
}
}
}
}
TArray<AHexTile*> Path;
AHexTile* Hex = Goal;
while (*Hex != *Start)
{
Path.Emplace(Hex);
Hex = Hex->CameFrom;
}
Algo::Reverse(Path);
return Path; // currently always length of 1
}