Compare commits
21 Commits
fc10cbfc3e
...
master
Author | SHA1 | Date | |
---|---|---|---|
276f8e2b50 | |||
068beeacfd | |||
18af6a56be | |||
26d3289962 | |||
28a226e35d | |||
aa02fb8093 | |||
21f7dd4e67 | |||
1485621698 | |||
1573598c2a | |||
2bf072e3c6 | |||
70ef60f08e | |||
b7b9963a68 | |||
986233d960 | |||
237c056b30 | |||
74eab48a6e | |||
239054df49 | |||
80e990c432 | |||
5c1535da32 | |||
6c1c0579cb | |||
32f4c6a278 | |||
180207f441 |
@ -18,9 +18,10 @@ AAdventureCameraPawn::AAdventureCameraPawn()
|
||||
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
BaseScrollSpeed = 20;
|
||||
ScrollAccelleration = BaseScrollSpeed * 3;
|
||||
|
||||
ESASize = .01;
|
||||
BaseScrollSpeed = 16;
|
||||
ScrollAccelleration = BaseScrollSpeed * 2.4;
|
||||
|
||||
ESAMaxBoundSlope = 1 / (1 - (1-ESASize));
|
||||
ESAMaxBoundIntercept = 1 - ESAMaxBoundSlope;
|
||||
@ -28,15 +29,16 @@ AAdventureCameraPawn::AAdventureCameraPawn()
|
||||
ESAMinBoundSlope = -1 / ESASize;
|
||||
ESAMinBoundIntercept = 0 - (ESAMinBoundSlope * ESASize);
|
||||
|
||||
AutoPossessPlayer = EAutoReceiveInput::Player0;
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void AAdventureCameraPawn::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
ControllerRef = (AAdventurePlayerController*)UGameplayStatics::GetPlayerController(GetWorld(), 0);
|
||||
OwningPC = (AAdventurePlayerController*)UGameplayStatics::GetPlayerController(GetWorld(), 0); // for now
|
||||
|
||||
// The Viewport properties are inaccurate right after BeginPlay, so we need to wait a short time before saving them here.
|
||||
// Viewport properties not accurate on BeginPlay (must wait before accessing)
|
||||
FTimerHandle UnusedHandle;
|
||||
GetWorldTimerManager().SetTimer(
|
||||
UnusedHandle, this, &AAdventureCameraPawn::GetTheDamnViewport, 1, false);
|
||||
@ -52,7 +54,11 @@ void AAdventureCameraPawn::GetTheDamnViewport()
|
||||
void AAdventureCameraPawn::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
if (IsValid(FollowPawn)) {
|
||||
if (FollowPawn->bIsMoving) {
|
||||
FollowAdvPawn(DeltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called to bind functionality to input
|
||||
@ -63,54 +69,68 @@ void AAdventureCameraPawn::SetupPlayerInputComponent(UInputComponent* PlayerInpu
|
||||
{
|
||||
PlayerInputComponent->BindAxis("Mouse X", this, &AAdventureCameraPawn::EdgeScrollSide);
|
||||
PlayerInputComponent->BindAxis("Mouse Y", this, &AAdventureCameraPawn::EdgeScrollVert);
|
||||
|
||||
PlayerInputComponent->BindAxis("Move AD", this, &AAdventureCameraPawn::ScrollSide);
|
||||
PlayerInputComponent->BindAxis("Move WS", this, &AAdventureCameraPawn::ScrollVert);
|
||||
}
|
||||
}
|
||||
|
||||
void AAdventureCameraPawn::ScrollSide(float AxisValue)
|
||||
{
|
||||
float DeltaLoc = AxisValue * BaseScrollSpeed * 1.7;
|
||||
AddActorLocalOffset(FVector(DeltaLoc, 0, 0));
|
||||
}
|
||||
|
||||
void AAdventureCameraPawn::ScrollVert(float AxisValue)
|
||||
{
|
||||
float DeltaLoc = AxisValue * BaseScrollSpeed * -1.7;
|
||||
AddActorLocalOffset(FVector(0, DeltaLoc, 0));
|
||||
}
|
||||
|
||||
void AAdventureCameraPawn::EdgeScrollSide(float AxisValue)
|
||||
{
|
||||
float mouseX;
|
||||
float mouseY;
|
||||
ControllerRef->GetMousePosition(mouseX, mouseY);
|
||||
OwningPC->GetMousePosition(mouseX, mouseY);
|
||||
float mousePosX = mouseX / ViewSize.X;
|
||||
float mousePosY = mouseY / ViewSize.Y;
|
||||
float VertAccelleration = GetInputAxisValue("Mouse Y") * (ScrollAccelleration * .75);
|
||||
|
||||
if (mousePosX <= ESASize) // if in LEFT area
|
||||
if (mousePosX <= ESASize) // in LEFT area
|
||||
{
|
||||
////// Scroll LEFT with Vert Accelleration
|
||||
////// Scroll LEFT
|
||||
float SpeedX = (mousePosX * ESAMinBoundSlope + ESAMinBoundIntercept) * BaseScrollSpeed;
|
||||
AddActorLocalOffset(FVector(0, -SpeedX, 0));
|
||||
AddActorLocalOffset(FVector(-SpeedX, 0, 0));
|
||||
|
||||
if (mousePosY > .005) // if not touching EDGE
|
||||
if (mousePosY > .005) // not touching TOP EDGE
|
||||
{
|
||||
AddActorLocalOffset(FVector(VertAccelleration, 0, 0));
|
||||
AddActorLocalOffset(FVector(0, -VertAccelleration, 0));
|
||||
}
|
||||
|
||||
if (AxisValue < .0 && mousePosX <= .005) // if mouse moving LEFT and touching EDGE
|
||||
if (AxisValue < .0 && mousePosX <= .005) // mouse moving LEFT && touching EDGE
|
||||
{
|
||||
////// Add LEFT accelleration
|
||||
SpeedX = AxisValue * ScrollAccelleration;
|
||||
AddActorLocalOffset(FVector(0, SpeedX, 0));
|
||||
AddActorLocalOffset(FVector(SpeedX, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (mousePosX >= 1-ESASize) // if in RIGHT area
|
||||
if (mousePosX >= 1-ESASize) // in RIGHT area
|
||||
{
|
||||
////// Scroll RIGHT with Vert Accelleration
|
||||
////// Scroll RIGHT
|
||||
float SpeedX = (mousePosX * ESAMaxBoundSlope + ESAMaxBoundIntercept) * BaseScrollSpeed;
|
||||
AddActorLocalOffset(FVector(0, SpeedX, 0));
|
||||
AddActorLocalOffset(FVector(SpeedX, 0, 0));
|
||||
|
||||
if (mousePosY < .995) // if not touching EDGE
|
||||
if (mousePosY < .995) // not touching BOT EDGE
|
||||
{
|
||||
AddActorLocalOffset(FVector(VertAccelleration, 0, 0));
|
||||
AddActorLocalOffset(FVector(0, -VertAccelleration, 0));
|
||||
}
|
||||
|
||||
if (AxisValue > .0 && mousePosX >= .995) // if mouse moving RIGHT and touching EDGE
|
||||
if (AxisValue > .0 && mousePosX >= .995) // mouse moving RIGHT && touching EDGE
|
||||
{
|
||||
////// Add RIGHT accelleration
|
||||
SpeedX = AxisValue * ScrollAccelleration;
|
||||
AddActorLocalOffset(FVector(0, SpeedX, 0));
|
||||
AddActorLocalOffset(FVector(SpeedX, 0, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -119,61 +139,53 @@ void AAdventureCameraPawn::EdgeScrollVert(float AxisValue)
|
||||
{
|
||||
float mouseX;
|
||||
float mouseY;
|
||||
ControllerRef->GetMousePosition(mouseX, mouseY);
|
||||
OwningPC->GetMousePosition(mouseX, mouseY);
|
||||
float mousePosY = mouseY / ViewSize.Y;
|
||||
float mousePosX = mouseX / ViewSize.X;
|
||||
float SideAccelleration = GetInputAxisValue("Mouse X") * (ScrollAccelleration * .75);
|
||||
|
||||
if (mousePosY <= ESASize) // if in TOP area
|
||||
if (mousePosY <= ESASize) // in TOP area
|
||||
{
|
||||
////// Scroll TOP with Side Accelleration
|
||||
////// Scroll TOP
|
||||
float SpeedY = (mousePosY * ESAMinBoundSlope + ESAMinBoundIntercept) * BaseScrollSpeed;
|
||||
AddActorLocalOffset(FVector(SpeedY, SideAccelleration, 0));
|
||||
AddActorLocalOffset(FVector(0, -SpeedY, 0));
|
||||
|
||||
if (mousePosX > .005) // if not touching EDGE
|
||||
if (mousePosX > .005) // not touching EDGE
|
||||
{
|
||||
AddActorLocalOffset(FVector(0, SideAccelleration, 0));
|
||||
AddActorLocalOffset(FVector(SideAccelleration, 0, 0));
|
||||
}
|
||||
|
||||
if (AxisValue > .0 && mousePosY <= .005) // if mouse moving TOP and touching EDGE
|
||||
if (AxisValue > .0 && mousePosY <= .005) // mouse moving TOP && touching EDGE
|
||||
{
|
||||
////// Add TOP accelleration
|
||||
SpeedY = AxisValue * ScrollAccelleration;
|
||||
AddActorLocalOffset(FVector(SpeedY, 0, 0));
|
||||
AddActorLocalOffset(FVector(0, -SpeedY, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (mousePosY >= 1-ESASize) // if in BOTTOM area
|
||||
if (mousePosY >= 1-ESASize) // in BOTTOM area
|
||||
{
|
||||
////// Scroll BOTTOM with Side Accelleration
|
||||
////// Scroll BOTTOM
|
||||
float SpeedY = (mousePosY * ESAMaxBoundSlope + ESAMaxBoundIntercept) * BaseScrollSpeed;
|
||||
AddActorLocalOffset(FVector(-SpeedY, SideAccelleration, 0));
|
||||
AddActorLocalOffset(FVector(0, SpeedY, 0));
|
||||
|
||||
if (mousePosX < .995) // if not touching EDGE
|
||||
if (mousePosX < .995) // not touching BOT EDGE
|
||||
{
|
||||
AddActorLocalOffset(FVector(0, SideAccelleration, 0));
|
||||
AddActorLocalOffset(FVector(SideAccelleration, 0, 0));
|
||||
}
|
||||
|
||||
if (AxisValue < .0 && mousePosY >= .995) // if mouse moving BOTTOM and touching EDGE
|
||||
if (AxisValue < .0 && mousePosY >= .995) // mouse moving BOTTOM && touching EDGE
|
||||
{
|
||||
////// add BOTTOM accelleration
|
||||
SpeedY = AxisValue * ScrollAccelleration;
|
||||
AddActorLocalOffset(FVector(SpeedY, 0, 0));
|
||||
AddActorLocalOffset(FVector(0, -SpeedY, 0));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void AAdventureCameraPawn::FollowAdvPawn()
|
||||
void AAdventureCameraPawn::FollowAdvPawn(float DeltaSeconds)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("following..."));
|
||||
|
||||
AdvPawnLocationCurrent = AdvPawnRef->GetActorLocation();
|
||||
AdvPawnLocationDelta = AdvPawnLocationCurrent - AdvPawnLocationPrevious;
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("%s"), *AdvPawnLocationDelta.ToString());
|
||||
|
||||
AddActorLocalOffset(AdvPawnLocationDelta);
|
||||
|
||||
AdvPawnLocationPrevious = AdvPawnLocationCurrent;
|
||||
bool MapPawnInViewX = (FMath::Abs(FollowPawn->GetActorTransform().GetLocation().X - this->GetActorLocation().X)) < ViewSize.X;
|
||||
bool MapPawnInViewY = (FMath::Abs(FollowPawn->GetActorTransform().GetLocation().Y - this->GetActorLocation().Y)) < ViewSize.Y;
|
||||
if (MapPawnInViewX && MapPawnInViewY) { AddActorLocalOffset(FollowPawn->GetVelocity() * DeltaSeconds); }
|
||||
}
|
@ -19,35 +19,24 @@ public:
|
||||
UGameViewportClient* Viewport;
|
||||
UPROPERTY()
|
||||
FIntPoint ViewSize;
|
||||
UPROPERTY()
|
||||
int32 TickIncrement = 0;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Config")
|
||||
class AAdventureMap* AdvMapRef;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Config")
|
||||
class AAdventurePlayerController* ControllerRef;
|
||||
class AAdventurePlayerController* OwningPC;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Config")
|
||||
class AAdventureCharacter* AdvPawnRef;
|
||||
class AAdventureCharacter* FollowPawn;
|
||||
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
|
||||
float ESASize;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
|
||||
float ScrollAccelleration;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
|
||||
float BaseScrollSpeed;
|
||||
|
||||
UPROPERTY()
|
||||
FVector AdvPawnLocationPrevious;
|
||||
UPROPERTY()
|
||||
FVector AdvPawnLocationCurrent;
|
||||
UPROPERTY()
|
||||
FVector AdvPawnLocationDelta;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Runtime")
|
||||
bool bAdvPawnIsMoving;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Runtime")
|
||||
class AHexTile* SelectedHex;
|
||||
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
@ -67,11 +56,15 @@ public:
|
||||
// Called to bind functionality to input
|
||||
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
|
||||
|
||||
UFUNCTION()
|
||||
void ScrollSide(float AxisValue);
|
||||
UFUNCTION()
|
||||
void ScrollVert(float AxisValue);
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EdgeScrollSide(float AxisValue);
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EdgeScrollVert(float AxisValue);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void FollowAdvPawn();
|
||||
void FollowAdvPawn(float DeltaSeconds);
|
||||
};
|
||||
|
@ -31,12 +31,4 @@ void AAdventureCharacter::Tick(float DeltaTime)
|
||||
void AAdventureCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
|
||||
}
|
||||
|
||||
void AAdventureCharacter::AStarFindPath(AHexTile* Goal)
|
||||
{
|
||||
std::priority_queue<int32> Frontier;
|
||||
TMap<AHexTile*, AHexTile*> CameFrom;
|
||||
TMap<AHexTile*, int32> CostSoFar;
|
||||
}
|
@ -20,14 +20,12 @@ public:
|
||||
// Sets default values for this character's properties
|
||||
AAdventureCharacter();
|
||||
|
||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Runtime")
|
||||
AHexTile* GridLocation;
|
||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Runtime")
|
||||
AHexTile* SelectedHex;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Config")
|
||||
class AAdventureMap* MapRef;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Runtime")
|
||||
TArray<AHexTile*> MovementPath;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void AStarFindPath(AHexTile* Goal);
|
||||
AHexTile* Location;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Runtime")
|
||||
bool bIsMoving;
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
|
379
AdventureMap.cpp
379
AdventureMap.cpp
@ -3,118 +3,383 @@
|
||||
|
||||
#include "AdventureMap.h"
|
||||
#include "HexTile.h"
|
||||
#include "AdventureCameraPawn.h"
|
||||
#include "AdventureCharacter.h"
|
||||
#include "StarFog.h"
|
||||
#include "AdventurePlayerController.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
#include "Algo/Reverse.h"
|
||||
#include "Util/IndexPriorityQueue.h"
|
||||
#include <tgmath.h>
|
||||
|
||||
// Sets default values
|
||||
AAdventureMap::AAdventureMap()
|
||||
{
|
||||
FHexVector NBs[] = { E, SSE, SSW, W, NNW, NNE };
|
||||
UnitVectors.Append(NBs, UE_ARRAY_COUNT(NBs));
|
||||
FHexVector DNBs[] = { N, ENE, ESE, S, WSW, WNW };
|
||||
DiagonalUnitVectors.Append(DNBs, UE_ARRAY_COUNT(DNBs));
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void AAdventureMap::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
UWorld* World = GetWorld();
|
||||
if (IsValid(BaseTileClass))
|
||||
{
|
||||
World = GetWorld();
|
||||
|
||||
if (IsValid(BaseTileClass)) {
|
||||
MakeGrid();
|
||||
}
|
||||
for (auto& Tile : Grid) {
|
||||
AStarFog* Fog = World->SpawnActor<AStarFog>(BaseFogClass, Tile->GetActorTransform());
|
||||
Fog->CoveredHex = Tile;
|
||||
Tile->CoveringFog = Fog;
|
||||
}
|
||||
}
|
||||
|
||||
// Called once on Begin Play
|
||||
void AAdventureMap::MakeGrid()
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
FVector NextHexAt = FVector();
|
||||
float HexWidth = sqrt(3) * TileSize;
|
||||
int QOffset = 0;
|
||||
|
||||
for (int r = 1; r <= GridSize; r++)
|
||||
{
|
||||
for (int r = 1; r <= GridSize; r++) {
|
||||
float XOffset = 0.f;
|
||||
if (r % 2 != 0) { if (r > 1) { QOffset--; } }
|
||||
else { XOffset = HexWidth / 2; }
|
||||
|
||||
if (r % 2 != 0)
|
||||
{
|
||||
if (r > 1)
|
||||
{
|
||||
QOffset--; // The Q axis is (i.e. columns are) oriented diagonally.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XOffset = HexWidth / 2;
|
||||
}
|
||||
|
||||
for (int q = 1; q <= GridSize; q++)
|
||||
{
|
||||
for (int q = 1; q <= GridSize; q++) {
|
||||
NextHexAt.X = XOffset + (HexWidth * q);
|
||||
NextHexAt.Y = TileSize * 1.5f * r;
|
||||
NextHexAt.Z = 0.f;
|
||||
|
||||
FTransform SpawnTransform = FTransform(NextHexAt);
|
||||
AHexTile* Tile = World->SpawnActor<AHexTile>(BaseTileClass, SpawnTransform);
|
||||
|
||||
Grid.Add(Tile);
|
||||
Tile->Q = q - 1 + QOffset;
|
||||
Tile->R = r - 1;
|
||||
|
||||
Grid.Add(Tile);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& tile : Grid)
|
||||
{
|
||||
for (auto& tile : Grid) {
|
||||
tile->Index = GridIndex(tile->Q, tile->R);
|
||||
}
|
||||
|
||||
bHexGridReady = true;
|
||||
}
|
||||
|
||||
// Every Hex Tile's index within the Grid Array can be derived from its Q and R coordinates
|
||||
// Every Hex Tile's index within the Grid Array can be derived from its Axial Q and R coordinates
|
||||
int32 AAdventureMap::GridIndex(int32 qAxial, int32 rAxial)
|
||||
{
|
||||
/*
|
||||
* The Q axis is (i.e. columns are) oriented diagonally.
|
||||
* The Hex Grid has a rough square shape, hence the Q coordinates must be offset by -1 every other row.
|
||||
*/
|
||||
int32 column = qAxial + FMath::FloorToInt(rAxial / 2);
|
||||
int32 column = qAxial + FMath::FloorToInt(rAxial / 2.);
|
||||
return (rAxial * GridSize) + column;
|
||||
}
|
||||
|
||||
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));
|
||||
//}
|
||||
//debug
|
||||
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Picking A Random Hex"));
|
||||
|
||||
int32 RandHex = FMath::RandRange(0, GridSize*GridSize-1);
|
||||
return Grid[RandHex];
|
||||
}
|
||||
|
||||
TArray<AHexTile*> AAdventureMap::Neighbors(AHexTile* OfHex)
|
||||
FHexVector AAdventureMap::AxialRound(float qf, float rf)
|
||||
{
|
||||
TArray<AHexTile*> Neighbors;
|
||||
int32 Index;
|
||||
float sf = -qf - rf;
|
||||
|
||||
Index = GridIndex(OfHex->Q + 1 , OfHex->R + 0 );
|
||||
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
|
||||
int32 q = round(qf);
|
||||
int32 r = round(rf);
|
||||
int32 s = round(sf);
|
||||
|
||||
Index = GridIndex(OfHex->Q + 1 , OfHex->R - 1 );
|
||||
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
|
||||
float q_diff = abs(q - qf);
|
||||
float r_diff = abs(r - rf);
|
||||
float s_diff = abs(s - sf);
|
||||
|
||||
Index = GridIndex(OfHex->Q + 0 , OfHex->R - 1 );
|
||||
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
|
||||
if (q_diff > r_diff && q_diff > s_diff)
|
||||
{ q = -r - s; }
|
||||
else if (r_diff > s_diff)
|
||||
{ r = -q - s; }
|
||||
else
|
||||
{ s = -q - r; }
|
||||
|
||||
Index = GridIndex(OfHex->Q - 1 , OfHex->R + 0 );
|
||||
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
|
||||
|
||||
Index = GridIndex(OfHex->Q - 1 , OfHex->R + 1 );
|
||||
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
|
||||
|
||||
Index = GridIndex(OfHex->Q + 0 , OfHex->R + 1 );
|
||||
if (Index >= 0 && Index < Grid.Num() && OfHex->Distance(Grid[Index]) == 1) { Neighbors.Add(Grid[Index]); }
|
||||
|
||||
return Neighbors;
|
||||
return FHexVector(q, r);
|
||||
}
|
||||
|
||||
float AAdventureMap::Lerp(int32 a, int32 b, float t)
|
||||
{
|
||||
return float(a + (b - a) * t);
|
||||
}
|
||||
|
||||
TArray<AHexTile*> AAdventureMap::Neighbors(AHexTile* OfHex, bool bFreeOnly = false)
|
||||
{
|
||||
TArray<AHexTile*> Results;
|
||||
for (FHexVector NeighborVector : UnitVectors) {
|
||||
int32 Index = GridIndex(OfHex->Q + NeighborVector.Q, OfHex->R + NeighborVector.R);
|
||||
if (Grid.IsValidIndex(Index)) {
|
||||
AHexTile* Hex = Grid[Index];
|
||||
if (bFreeOnly && !Hex->bFree) { continue; }
|
||||
if (Hex->Distance(OfHex) == 1) { Results.Add(Hex); }
|
||||
}
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
||||
TArray<AHexTile*> AAdventureMap::FreeDiagonals(AHexTile* OfHex)
|
||||
{
|
||||
TArray<AHexTile*> Results;
|
||||
for (auto& V : DiagonalUnitVectors) {
|
||||
int32 I = GridIndex(OfHex->Q + V.Q, OfHex->R + V.R);
|
||||
if (!Grid.IsValidIndex(I)) { continue; }
|
||||
else {
|
||||
bool bReachable = true;
|
||||
for (AHexTile* PotentialBlock : Neighbors(OfHex)) {
|
||||
if (PotentialBlock->Distance(Grid[I]) != 1) { continue; }
|
||||
if (!PotentialBlock->bFree) {
|
||||
bReachable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bReachable) { Results.Add(Grid[I]); }
|
||||
}
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
||||
TSet<AHexTile*> AAdventureMap::BreadthFirstSearch(AHexTile* Start, int32 Radius)
|
||||
{
|
||||
TSet<AHexTile*> Results;
|
||||
TArray<AHexTile*> Frontier;
|
||||
TSet<AHexTile*> Processed;
|
||||
Results.Add(Start);
|
||||
Frontier.Add(Start);
|
||||
|
||||
while (!Frontier.IsEmpty()) {
|
||||
AHexTile* Current = Frontier[0];
|
||||
Processed.Add(Current);
|
||||
Frontier.Remove(Current);
|
||||
|
||||
for (AHexTile* Neighbor : Neighbors(Current)) {
|
||||
if (Neighbor->Distance(Current) > 1) { continue; }
|
||||
if (Processed.Contains(Neighbor)) { continue; }
|
||||
if (Neighbor->Distance(Start) > Radius) { continue; }
|
||||
|
||||
Frontier.Add(Neighbor);
|
||||
Results.Add(Neighbor);
|
||||
}
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* // Faulty implementation which uses an actual PriorityQueue
|
||||
TArray<AHexTile*> AAdventureMap::FindPathAStar(AHexTile* Start, AHexTile* Goal, bool bDiags)
|
||||
{
|
||||
|
||||
TSet<AHexTile*> Processed;
|
||||
TSet<AHexTile*> ToSearch;
|
||||
TPriorityQueue<AHexTile*> Frontier;
|
||||
|
||||
Start->GCost = 0;
|
||||
Frontier.Push(Start, .0f);
|
||||
ToSearch.Add(Start);
|
||||
|
||||
while (!Frontier.IsEmpty()) {
|
||||
AHexTile* Current = Frontier.Pop();
|
||||
ToSearch.Remove(Current);
|
||||
|
||||
if (Current == Goal) { break; }
|
||||
Processed.Add(Current);
|
||||
|
||||
for (AHexTile* Neighbor : Neighbors(Current, true)) {
|
||||
if (Processed.Contains(Neighbor)) { continue; }
|
||||
bool bInToSearch = ToSearch.Contains(Start);
|
||||
|
||||
int32 NewGCost = Current->GCost + Neighbor->MoveCost;
|
||||
|
||||
if (!bInToSearch || NewGCost < Neighbor->GCost) {
|
||||
Neighbor->GCost = NewGCost;
|
||||
Neighbor->CameFrom = Current;
|
||||
|
||||
if (!bInToSearch) {
|
||||
Neighbor->HCost = Neighbor->Distance(Goal);
|
||||
Frontier.Push(Neighbor, NewGCost + Neighbor->HCost);
|
||||
ToSearch.Add(Neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<AHexTile*> Path;
|
||||
if (!IsValid(Goal->CameFrom)) { return Path; }
|
||||
AHexTile* iPathNode = Goal;
|
||||
while (iPathNode != Start) {
|
||||
Path.Emplace(iPathNode);
|
||||
iPathNode = iPathNode->CameFrom;
|
||||
}
|
||||
Algo::Reverse(Path);
|
||||
return Path;
|
||||
}
|
||||
*/
|
||||
|
||||
TArray<AHexTile*> AAdventureMap::FindPathAStar(AHexTile * Start, AHexTile * Goal, bool bDiags)
|
||||
{
|
||||
TArray<AHexTile*> Frontier;
|
||||
TSet<AHexTile*> Processed;
|
||||
Frontier.Add(Start);
|
||||
while (!Frontier.IsEmpty()) {
|
||||
// Pop
|
||||
AHexTile* Candidate = Frontier[0];
|
||||
|
||||
// Exit
|
||||
if (Candidate == Goal) { break; }
|
||||
|
||||
// Find contender with an even lower F-cost
|
||||
for (AHexTile* Other : Frontier) {
|
||||
if (Other->FCost < Candidate->FCost
|
||||
|| Other->FCost == Candidate->FCost && Other->HCost < Candidate->HCost)
|
||||
{ Candidate = Other; }
|
||||
}
|
||||
|
||||
Frontier.Remove(Candidate);
|
||||
Processed.Add(Candidate);
|
||||
// Expand frontier, make connections when appropriate
|
||||
for (AHexTile* Neighbor : Neighbors(Candidate, true)) {
|
||||
if (Processed.Contains(Neighbor)) { continue; }
|
||||
|
||||
bool bInFrontier = Frontier.Contains(Neighbor);
|
||||
int32 NewGCost = Candidate->GCost + Neighbor->MoveCost;
|
||||
|
||||
if (NewGCost < Neighbor->GCost || !bInFrontier) {
|
||||
Neighbor->GCost = NewGCost;
|
||||
Neighbor->HCost = Neighbor->Distance(Goal);
|
||||
Neighbor->FCost = Neighbor->GCost + Neighbor->HCost;
|
||||
Neighbor->CameFrom = Candidate; // chain
|
||||
if (!bInFrontier) {
|
||||
Frontier.Add(Neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build and return path
|
||||
TArray<AHexTile*> Path;
|
||||
AHexTile* iPathNode = Goal;
|
||||
while (iPathNode != Start) {
|
||||
if (!IsValid(iPathNode->CameFrom) || !iPathNode->bFree) {
|
||||
Path.Empty();
|
||||
return Path;
|
||||
}
|
||||
Path.Emplace(iPathNode);
|
||||
iPathNode = iPathNode->CameFrom;
|
||||
}
|
||||
Algo::Reverse(Path);
|
||||
return Path;
|
||||
}
|
||||
|
||||
// very bro-sciency approach to pathfinding for diagonal Hex-movement
|
||||
// DO NOT USE
|
||||
TArray<AHexTile*> AAdventureMap::ShortcutAStar(TArray<AHexTile*> Path)
|
||||
{
|
||||
TArray<AHexTile*> Shortcut;
|
||||
|
||||
int32 Len = Path.Num();
|
||||
TArray<AHexTile*> WorkingSegment;
|
||||
AHexTile* CurrentHex = PCRef->CurrentHex;
|
||||
WorkingSegment.Add(CurrentHex);
|
||||
int32 h = 0;
|
||||
|
||||
// create segments for each bend
|
||||
FHexVector PrevDir = FHexVector(Path[0], CurrentHex);
|
||||
FHexVector DirASave = PrevDir;
|
||||
FHexVector DirA;
|
||||
int32 HexesBeforeBend = 1;
|
||||
for (h; h < Len-1; h++) {
|
||||
WorkingSegment.Add(Path[h]);
|
||||
DirA = FHexVector(Path[h+1], Path[h]);
|
||||
if (DirA != PrevDir) { break; } // save Path[h] into Array of Bends
|
||||
HexesBeforeBend++;
|
||||
PrevDir = DirA;
|
||||
}
|
||||
PrevDir = DirA;
|
||||
FHexVector DirB;
|
||||
int32 HexesAfterBend = 0;
|
||||
for (h; h < Len - 1; h++) {
|
||||
WorkingSegment.Add(Path[h+1]);
|
||||
DirB = FHexVector(Path[h+1], Path[h]);
|
||||
if (DirB != PrevDir) { break; }
|
||||
HexesAfterBend++;
|
||||
PrevDir = DirB;
|
||||
}
|
||||
|
||||
if (HexesAfterBend == 0)
|
||||
{ return Path; }
|
||||
FHexVector UnitDiag = UnitDiagFromUnitNB(DirASave, DirB);
|
||||
AHexTile* Milestone = WorkingSegment.Last();
|
||||
int32 NumDiags = (HexesBeforeBend >= HexesAfterBend) ? HexesAfterBend : HexesBeforeBend;
|
||||
int32 NumTries = (HexesBeforeBend >= HexesAfterBend) ? HexesBeforeBend : HexesAfterBend;
|
||||
|
||||
bool bDiagAdded = false;
|
||||
for (int i = 0; i < NumTries; i++) {
|
||||
if (NumDiags == 0) {
|
||||
Shortcut.Append(FindPathAStar(CurrentHex, Milestone, false));
|
||||
break;
|
||||
}
|
||||
if (DiagIsReachable(CurrentHex, UnitDiag)) {
|
||||
int32 CanIndex = GridIndex(CurrentHex->Q + UnitDiag.Q, CurrentHex->R + UnitDiag.R);
|
||||
if (Grid.IsValidIndex(CanIndex)) {
|
||||
AHexTile* Current = Grid[CanIndex];
|
||||
if (Current->bFree) {
|
||||
Shortcut.Add(Current);
|
||||
bDiagAdded = true;
|
||||
CurrentHex = Current;
|
||||
NumDiags--;
|
||||
continue;
|
||||
} } }
|
||||
if (!bDiagAdded && !DiagIsReachable(CurrentHex, UnitDiag)) {
|
||||
Shortcut.Add(CurrentHex);
|
||||
CurrentHex = WorkingSegment[i + 1];
|
||||
NumDiags--;
|
||||
continue;
|
||||
}
|
||||
if (bDiagAdded && !DiagIsReachable(CurrentHex, UnitDiag)) {
|
||||
Shortcut.Append(FindPathAStar(CurrentHex, Milestone, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Milestone != Path.Last()) { Shortcut.Append(FindPathAStar(Milestone, Path.Last(), true)); }
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("Hexes before bend: %d"), HexesBeforeBend);
|
||||
UE_LOG(LogTemp, Warning, TEXT("Hexes after bend: %d"), HexesAfterBend);
|
||||
|
||||
return Shortcut;
|
||||
}
|
||||
|
||||
FHexVector AAdventureMap::UnitDiagFromUnitNB(FHexVector InVecA, FHexVector InVecB) {
|
||||
if (InVecA == NNW && InVecB == NNE||InVecB == NNW && InVecA == NNE) { return N; }
|
||||
if (InVecA == NNE && InVecB == E ||InVecB == NNE && InVecA == E) { return ENE; }
|
||||
if (InVecA == E && InVecB == SSE||InVecB == E && InVecA == SSE) { return ESE; }
|
||||
if (InVecA == SSE && InVecB == SSW||InVecB == SSE && InVecA == SSW) { return S; }
|
||||
if (InVecA == SSW && InVecB == W ||InVecB == SSW && InVecA == W) { return WSW; }
|
||||
if (InVecA == W && InVecB == NNW||InVecB == W && InVecA == NNW) { return WNW; }
|
||||
return FHexVector();
|
||||
}
|
||||
|
||||
bool AAdventureMap::DiagIsReachable(AHexTile* InStart, FHexVector InDiagUnitVec) {
|
||||
FHexVector BlockA;
|
||||
FHexVector BlockB;
|
||||
if (InDiagUnitVec == N) { BlockA = NNW, BlockB = NNE; }
|
||||
if (InDiagUnitVec == ENE) { BlockA = NNE, BlockB = E; }
|
||||
if (InDiagUnitVec == ESE) { BlockA = E, BlockB = SSE; }
|
||||
if (InDiagUnitVec == S) { BlockA = SSE, BlockB = SSW; }
|
||||
if (InDiagUnitVec == WSW) { BlockA = SSW, BlockB = W; }
|
||||
if (InDiagUnitVec == WNW) { BlockA = W, BlockB = NNW; }
|
||||
int32 IndexA = GridIndex(InStart->Q + BlockA.Q, InStart->R + BlockA.R);
|
||||
int32 IndexB = GridIndex(InStart->Q + BlockB.Q, InStart->R + BlockB.R);
|
||||
if (!Grid.IsValidIndex(IndexA) || !Grid.IsValidIndex(IndexB)) { return false; }
|
||||
AHexTile* HexA = Grid[IndexA];
|
||||
AHexTile* HexB = Grid[IndexB];
|
||||
return (HexA->bFree && HexB->bFree);
|
||||
}
|
||||
|
||||
|
150
AdventureMap.h
150
AdventureMap.h
@ -1,13 +1,15 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Containers/Map.h"
|
||||
#include "HexVector.h"
|
||||
#include "AdventureMap.generated.h"
|
||||
|
||||
class AHexTile;
|
||||
class AAdventureCharacter;
|
||||
class AStarFog;
|
||||
class AMapObject;
|
||||
class AAdventurePlayerController;
|
||||
|
||||
UCLASS()
|
||||
class FRAY_API AAdventureMap : public AActor
|
||||
@ -18,36 +20,154 @@ public:
|
||||
// Sets default values for this actor's properties
|
||||
AAdventureMap();
|
||||
|
||||
UPROPERTY()
|
||||
UWorld* World;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config")
|
||||
TSubclassOf<AHexTile> BaseTileClass;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config")
|
||||
TSubclassOf<ACharacter> BasePartyCharacterClass;
|
||||
TSubclassOf<AStarFog> BaseFogClass;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config")
|
||||
int32 GridSize = 100; // squared is the number of Tiles
|
||||
int32 GridSize = 60;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config")
|
||||
int32 TileSize = 100;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
AAdventurePlayerController* PCRef;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Generation")
|
||||
void MakeGrid();
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Generation")
|
||||
bool bHexGridReady;
|
||||
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Generation")
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Generation")
|
||||
TArray<AHexTile*> Grid;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime")
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
int32 GridIndex(int32 q, int32 r);
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime")
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
AHexTile* RandomHex();
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime")
|
||||
TArray<AHexTile*> Neighbors(AHexTile* OfHex);
|
||||
|
||||
// Player spawn section
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
APawn* CameraPawn;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
AAdventureCharacter* PlayerCharacter;
|
||||
// Cardinal direction vectors
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag
|
||||
FHexVector N = FHexVector(1, -2); //
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
FHexVector NNE = FHexVector(1, -1);
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag
|
||||
FHexVector ENE = FHexVector(2, -1); //
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
FHexVector E = FHexVector(1, 0);
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag
|
||||
FHexVector ESE = FHexVector(1, 1); //
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
FHexVector SSE = FHexVector(0, 1);
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag
|
||||
FHexVector S = FHexVector(-1, 2); //
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
FHexVector SSW = FHexVector(-1, 1);
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag
|
||||
FHexVector WSW = FHexVector(-2, 1); //
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
FHexVector W = FHexVector(-1, 0);
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag
|
||||
FHexVector WNW = FHexVector(-1, -1); //
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
FHexVector NNW = FHexVector(0, -1);
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
TArray<FHexVector> UnitVectors;
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
TArray<FHexVector> DiagonalUnitVectors;
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
FHexVector UnitDiagFromUnitNB(FHexVector InVecA, FHexVector InVecB);
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
bool DiagIsReachable(AHexTile* InStart, FHexVector InDiagUnitVec);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
float Lerp(int32 a, int32 b, float t);
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
FHexVector AxialRound(float q, float r);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
TArray<AHexTile*> Neighbors(AHexTile* OfHex, bool bFreeOnly);
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
TArray<AHexTile*> FreeDiagonals(AHexTile* OfHex);
|
||||
UFUNCTION(BlueprintCallable, Category = "Utility")
|
||||
TSet<AHexTile*> BreadthFirstSearch(AHexTile* Start, int32 Radius);
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime")
|
||||
TArray<AHexTile*> FindPathAStar(AHexTile* Start, AHexTile* Goal, bool bDiags);
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime")
|
||||
TArray<AHexTile*> ShortcutAStar(TArray<AHexTile*> Path);
|
||||
|
||||
|
||||
// considering a MapObjectManager class or moving pathfinding & search to PlayerController
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
TMap<AHexTile*, AMapObject*> MapObjects;
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
TMap<int32, AMapObject*> MapObjectsByID;
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere)
|
||||
int32 IncID = -1;
|
||||
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
};
|
||||
|
||||
|
||||
// only used for an experimental implementation of A*
|
||||
template <typename InElementType>
|
||||
struct TPriorityQueueNode {
|
||||
InElementType Element;
|
||||
float Priority;
|
||||
|
||||
TPriorityQueueNode()
|
||||
{
|
||||
}
|
||||
|
||||
TPriorityQueueNode(InElementType InElement, float InPriority)
|
||||
{
|
||||
Element = InElement;
|
||||
Priority = InPriority;
|
||||
}
|
||||
|
||||
bool operator<(const TPriorityQueueNode<InElementType> Other) const
|
||||
{
|
||||
return Priority < Other.Priority;
|
||||
}
|
||||
};
|
||||
template <typename InElementType>
|
||||
class TPriorityQueue {
|
||||
public:
|
||||
TPriorityQueue()
|
||||
{
|
||||
Array.Heapify();
|
||||
}
|
||||
|
||||
public:
|
||||
// Always check if IsEmpty() before Pop-ing!
|
||||
InElementType Pop()
|
||||
{
|
||||
TPriorityQueueNode<InElementType> Node;
|
||||
Array.HeapPop(Node);
|
||||
return Node.Element;
|
||||
}
|
||||
|
||||
TPriorityQueueNode<InElementType> PopNode()
|
||||
{
|
||||
TPriorityQueueNode<InElementType> Node;
|
||||
Array.HeapPop(Node);
|
||||
return Node;
|
||||
}
|
||||
|
||||
void Push(InElementType Element, float Priority)
|
||||
{
|
||||
Array.HeapPush(TPriorityQueueNode<InElementType>(Element, Priority));
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return Array.Num() == 0;
|
||||
}
|
||||
|
||||
public: // make private later on
|
||||
TArray<TPriorityQueueNode<InElementType>> Array;
|
||||
};
|
@ -6,11 +6,141 @@
|
||||
#include "HexTile.h"
|
||||
#include "AdventureCameraPawn.h"
|
||||
#include "AdventureCharacter.h"
|
||||
#include "MapObject.h"
|
||||
#include "MovementArrow.h"
|
||||
|
||||
|
||||
|
||||
AAdventurePlayerController::AAdventurePlayerController()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
PrimaryActorTick.bStartWithTickEnabled = true;
|
||||
|
||||
AutoReceiveInput = EAutoReceiveInput::Player0;
|
||||
}
|
||||
void AAdventurePlayerController::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
World = GetWorld();
|
||||
|
||||
HoveredHex = CurrentHex;
|
||||
|
||||
}
|
||||
// Called every frame
|
||||
void AAdventurePlayerController::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
if (bInPlacementMode) { FitOnGrid(PlaceObj); }
|
||||
}
|
||||
|
||||
void AAdventurePlayerController::SetupInputComponent()
|
||||
{
|
||||
// Always call this.
|
||||
Super::SetupInputComponent();
|
||||
|
||||
// This is initialized on startup, you can go straight to binding
|
||||
InputComponent->BindAction("LeftClick", IE_Pressed, this, &AAdventurePlayerController::LeftClick);
|
||||
InputComponent->BindAction("DebugAlt", IE_Pressed, this, &AAdventurePlayerController::EnablePlacing); // Change binding eventually
|
||||
InputComponent->BindAction("DebugAlt", IE_Released, this, &AAdventurePlayerController::DisablePlacing); // Change binding eventually
|
||||
}
|
||||
|
||||
void AAdventurePlayerController::LeftClick()
|
||||
{
|
||||
if (IsValid(HoveredHex)) {
|
||||
if (!bInPlacementMode) {
|
||||
|
||||
}
|
||||
else { PlaceObject(PlaceObjClass, HoveredHex); }
|
||||
}
|
||||
else { return; }
|
||||
}
|
||||
|
||||
TArray<AHexTile*> AAdventurePlayerController::Vision(int32 Radius)
|
||||
{
|
||||
TSet<AHexTile*> InRange = MapRef->BreadthFirstSearch(CurrentHex, Radius);
|
||||
TArray<AHexTile*> Results;
|
||||
|
||||
for (auto& Hex : InRange) {
|
||||
if (Hex->Distance(CurrentHex) == Radius)
|
||||
{
|
||||
for (int32 i = 1; i <= Radius; i++)
|
||||
{
|
||||
float t = 1.0f / Radius * i;
|
||||
FHexVector Sample;
|
||||
|
||||
Sample = MapRef->AxialRound(MapRef->Lerp(CurrentHex->Q, Hex->Q, t), MapRef->Lerp(CurrentHex->R, Hex->R, t));
|
||||
AHexTile* SampleHex = MapRef->Grid[MapRef->GridIndex(Sample.Q, Sample.R)];
|
||||
|
||||
Results.Add(SampleHex);
|
||||
|
||||
if (!ExploredHexes.Contains(SampleHex))
|
||||
{ ExploredHexes.Add(Hex); }
|
||||
|
||||
if (!SampleHex->bFree)
|
||||
{ break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
||||
void AAdventurePlayerController::MarkPath(TArray<AHexTile*> Path)
|
||||
{
|
||||
if (Path.IsEmpty()) { return; }
|
||||
else if (!IsValid(Path[0])) { return; }
|
||||
else if (CurrentHex->Distance(Path[0])>1) { return; }
|
||||
|
||||
FHexVector DirA = FHexVector(Path[0]->Q - CurrentHex->Q, Path[0]->R - CurrentHex->R);
|
||||
FHexVector DirB;
|
||||
for (int32 i = 0; i < Path.Num() - 1; i++)
|
||||
{
|
||||
DirB = FHexVector(Path[i + 1]->Q - Path[i]->Q, Path[i + 1]->R - Path[i]->R);
|
||||
AMovementArrow* Arrow = World->SpawnActor<AMovementArrow>(MoveArrowClass, Path[i]->GetActorTransform());
|
||||
Arrow->MapRef = MapRef;
|
||||
Arrow->SetVariant(DirA, DirB);
|
||||
PathArrows.Add(Arrow);
|
||||
DirA = DirB;
|
||||
}
|
||||
}
|
||||
void AAdventurePlayerController::ClearPath()
|
||||
{
|
||||
for (AMovementArrow* Arrow : PathArrows) {
|
||||
Arrow->Destroy();
|
||||
}
|
||||
PathArrows.Empty();
|
||||
}
|
||||
|
||||
void AAdventurePlayerController::EnablePlacing()
|
||||
{
|
||||
bInPlacementMode = true;
|
||||
PlaceObj = World->SpawnActor<AMapObject>(PlaceObjClass, FTransform());
|
||||
}
|
||||
|
||||
void AAdventurePlayerController::DisablePlacing()
|
||||
{
|
||||
bInPlacementMode = false;
|
||||
// if (IsValid(PlaceObj)) { PlaceObj->Destroy(); }
|
||||
}
|
||||
|
||||
void AAdventurePlayerController::FitOnGrid(AMapObject* MapObject)
|
||||
{
|
||||
if (!IsValid(HoveredHex)) { return; }
|
||||
if (HoveredHex->bFree) { MapObject->SetActorLocation(FVector(HoveredHex->GetActorLocation())); }
|
||||
}
|
||||
|
||||
// To-Do: factor out core functionality to a seperate (more neutral) class like AdventureMap.
|
||||
void AAdventurePlayerController::PlaceObject(TSubclassOf<AMapObject> MapObjClass, AHexTile* HoveredTile)
|
||||
{
|
||||
AMapObject* SpawnedObj = World->SpawnActor<AMapObject>(MapObjClass, FTransform(HoveredTile->GetActorTransform().GetLocation()));
|
||||
SpawnedObj->MapRef = MapRef;
|
||||
SpawnedObj->Origin = HoveredTile;
|
||||
SpawnedObj->bPlaced = true;
|
||||
HoveredTile->bFree = false;
|
||||
HoveredTile->MapObject = SpawnedObj;
|
||||
|
||||
MapRef->MapObjects.Add(HoveredTile, SpawnedObj);
|
||||
MapRef->IncID++;
|
||||
SpawnedObj->ID = MapRef->IncID;
|
||||
MapRef->MapObjectsByID.Add(MapRef->IncID, SpawnedObj);
|
||||
SpawnedObj->Occupy();
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
@ -11,6 +9,8 @@ class AAdventureMap;
|
||||
class AHexTile;
|
||||
class AAdventureCameraPawn;
|
||||
class AAdventureCharacter;
|
||||
class AMapObject;
|
||||
class AMovementArrow;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -23,5 +23,66 @@ class FRAY_API AAdventurePlayerController : public APlayerController
|
||||
public:
|
||||
AAdventurePlayerController();
|
||||
|
||||
// General
|
||||
UPROPERTY()
|
||||
UWorld* World;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
AAdventureMap* MapRef;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
AAdventureCameraPawn* CamRef;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
AHexTile* SpawnHex;
|
||||
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Runtime")
|
||||
AHexTile* CurrentHex;
|
||||
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
AHexTile* HoveredHex;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void LeftClick();
|
||||
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
|
||||
TSubclassOf<AMovementArrow> MoveArrowClass;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void MarkPath(TArray<AHexTile*> Path);
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere)
|
||||
TArray<AMovementArrow*> PathArrows;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void ClearPath();
|
||||
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 VisionRadius = 6;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
TArray<AHexTile*> Vision(int32 Radius);
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TSet<AHexTile*> ExploredHexes;
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
virtual void SetupInputComponent() override;
|
||||
|
||||
public:
|
||||
|
||||
// Object Placement
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere)
|
||||
bool bInPlacementMode;
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
TSubclassOf<AMapObject> PlaceObjClass;
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere)
|
||||
AMapObject* PlaceObj;
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnablePlacing();
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisablePlacing();
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void FitOnGrid(AMapObject* MapObject);
|
||||
UFUNCTION()
|
||||
void PlaceObject(TSubclassOf<AMapObject> MapObjClass, AHexTile* OnHex);
|
||||
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
};
|
||||
|
@ -1,34 +0,0 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Clickable.h"
|
||||
|
||||
// Sets default values for this component's properties
|
||||
UClickable::UClickable()
|
||||
{
|
||||
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
|
||||
// off to improve performance if you don't need them.
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
// Called when the game starts
|
||||
void UClickable::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Called every frame
|
||||
void UClickable::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
28
Clickable.h
28
Clickable.h
@ -1,28 +0,0 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "Clickable.generated.h"
|
||||
|
||||
|
||||
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||
class FRAY_API UClickable : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Sets default values for this component's properties
|
||||
UClickable();
|
||||
|
||||
protected:
|
||||
// Called when the game starts
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
|
||||
};
|
18
HexTile.cpp
18
HexTile.cpp
@ -10,40 +10,26 @@
|
||||
AHexTile::AHexTile()
|
||||
{
|
||||
TileSize = 100.f;
|
||||
|
||||
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
|
||||
|
||||
this->FillCornersArray();
|
||||
}
|
||||
|
||||
void AHexTile::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
}
|
||||
void AHexTile::BeginPlay() { Super::BeginPlay(); }
|
||||
|
||||
FVector AHexTile::Corner(int32 i)
|
||||
{
|
||||
FVector TileCenter = this->GetActorTransform().GetLocation();
|
||||
|
||||
int32 Angle_Deg = 60 * i - 30;
|
||||
float Angle_Rad = UKismetMathLibrary::GetPI()/180 * Angle_Deg;
|
||||
float X = TileCenter.X + TileSize * cos(Angle_Rad);
|
||||
float Y = TileCenter.Y + TileSize * sin(Angle_Rad);
|
||||
|
||||
return FVector(X, Y, 0.f);
|
||||
}
|
||||
void AHexTile::FillCornersArray()
|
||||
{
|
||||
for (int32 i = 0 ; i < 6; i++)
|
||||
{
|
||||
Corners.Emplace(Corner(i + 1));
|
||||
}
|
||||
}
|
||||
void AHexTile::FillCornersArray() { for (int32 i = 0 ; i < 6; i++) { Corners.Emplace(Corner(i + 1)); } }
|
||||
|
||||
int32 AHexTile::Distance(AHexTile* ToHex)
|
||||
{
|
||||
int32 CubeS1 = -this->Q - this->R;
|
||||
int32 CubeS2 = -ToHex->Q - ToHex->R;
|
||||
|
||||
return (abs(this->Q - ToHex->Q) + abs(this->R - ToHex->R) + abs(CubeS1 - CubeS2)) / 2;
|
||||
}
|
60
HexTile.h
60
HexTile.h
@ -1,5 +1,3 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
@ -10,6 +8,8 @@
|
||||
class USceneComponent;
|
||||
class UStaticMeshComponent;
|
||||
class AAdventureMap;
|
||||
class AMapObject;
|
||||
class AStarFog;
|
||||
class AAdventurePlayerController;
|
||||
|
||||
UCLASS()
|
||||
@ -23,31 +23,65 @@ public:
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config")
|
||||
float TileSize;
|
||||
//UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Config")
|
||||
// USceneComponent* SceneComponent;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Config")
|
||||
AAdventureMap* MapRef;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Config")
|
||||
AStarFog* CoveringFog;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
|
||||
USceneComponent* SceneComponent;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "debug")
|
||||
FVector Corner(int32 i);
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "debug")
|
||||
TArray<FVector> Corners;
|
||||
UFUNCTION()
|
||||
void FillCornersArray();
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "debug")
|
||||
TArray<FVector> Corners;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Runtime")
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Coordinates")
|
||||
int32 Q;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Runtime")
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Coordinates")
|
||||
int32 R;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Runtime")
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Coordinates")
|
||||
int32 Index;
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Runtime")
|
||||
AAdventureMap* MapRef;
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime")
|
||||
UFUNCTION(BlueprintCallable, Category = "Coordinates")
|
||||
int32 Distance(AHexTile* ToHex);
|
||||
|
||||
// Pathfinding
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
int32 MoveCost = 1;
|
||||
UPROPERTY()
|
||||
int32 FCost;
|
||||
UPROPERTY()
|
||||
int32 GCost = 9999;
|
||||
UPROPERTY()
|
||||
int32 HCost;
|
||||
UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category = "Runtime")
|
||||
AHexTile* CameFrom;
|
||||
|
||||
// MapObject Placement
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere)
|
||||
bool bFree = true;
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere)
|
||||
AMapObject* MapObject;
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly)
|
||||
bool bCanActivate = false;
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly)
|
||||
bool bEvent = false;
|
||||
|
||||
FORCEINLINE bool operator == (const AHexTile &Other)
|
||||
{
|
||||
if (this->Q == Other.Q && this->R == Other.R) { return true; }
|
||||
else { return false; }
|
||||
}
|
||||
FORCEINLINE bool operator != (const AHexTile &Other)
|
||||
{
|
||||
if (this->Q == Other.Q && this->R == Other.R) { return false; }
|
||||
else { return true; }
|
||||
}
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
};
|
||||
|
||||
|
56
HexVector.h
Normal file
56
HexVector.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "HexTile.h"
|
||||
#include "HexVector.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHexVector
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FORCEINLINE FHexVector();
|
||||
FORCEINLINE explicit FHexVector(int32 InQ, int32 InR);
|
||||
FORCEINLINE explicit FHexVector(int32 InQ, int32 InR, bool bInDiag, bool bInUnit);
|
||||
FORCEINLINE explicit FHexVector(AHexTile* InHex);
|
||||
FORCEINLINE explicit FHexVector(AHexTile* InHexA, AHexTile* InHexB);
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
int32 Q;
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
int32 R;
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
int32 S;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
bool bIsDiagonal;
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
bool bUnit;
|
||||
};
|
||||
|
||||
FORCEINLINE FHexVector::FHexVector()
|
||||
{}
|
||||
FORCEINLINE FHexVector::FHexVector(int32 InQ, int32 InR)
|
||||
: Q(InQ), R(InR) {}
|
||||
FORCEINLINE FHexVector::FHexVector(int32 InQ, int32 InR, bool InIsDiag, bool InIsUnit)
|
||||
: Q(InQ), R(InR), bIsDiagonal(InIsDiag), bUnit(InIsUnit) {}
|
||||
FORCEINLINE FHexVector::FHexVector(AHexTile* InHex)
|
||||
: Q(InHex->Q), R(InHex->R) {}
|
||||
FORCEINLINE FHexVector::FHexVector(AHexTile* InHexA, AHexTile* InHexB)
|
||||
: Q(InHexA->Q - InHexB->Q), R(InHexA->R - InHexB->R) {}
|
||||
|
||||
FORCEINLINE bool operator==(const FHexVector& A, const FHexVector& B)
|
||||
{
|
||||
if (A.Q == B.Q && A.R == B.R) { return true; }
|
||||
else { return false; }
|
||||
}
|
||||
FORCEINLINE bool operator!=(const FHexVector& A, const FHexVector& B)
|
||||
{
|
||||
if (A.Q == B.Q && A.R == B.R) { return false; }
|
||||
else { return true; }
|
||||
}
|
||||
|
||||
FORCEINLINE uint32 GetTypeHash(const FHexVector& Thing)
|
||||
{
|
||||
uint32 Hash = FCrc::MemCrc32(&Thing, sizeof(FHexVector));
|
||||
return Hash;
|
||||
}
|
47
MapObject.cpp
Normal file
47
MapObject.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "MapObject.h"
|
||||
#include "AdventureMap.h"
|
||||
#include "HexTile.h"
|
||||
|
||||
// Sets default values
|
||||
AMapObject::AMapObject()
|
||||
{
|
||||
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
|
||||
RootComponent = SceneComponent;
|
||||
OrientHexMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Orient"));
|
||||
OrientHexMesh->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void AMapObject::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void AMapObject::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
}
|
||||
|
||||
void AMapObject::Touch()
|
||||
{
|
||||
}
|
||||
|
||||
void AMapObject::Activate()
|
||||
{
|
||||
}
|
||||
|
||||
// Any subclass of MapObject has a defined array of Vectors relative to its origin which has to occupy() upon being placed on the map.
|
||||
//void AMapObject::Occupy(int32 Q, int32 R)
|
||||
//{
|
||||
// AHexTile* OccupiedHex = MapRef->Grid[MapRef->GridIndex(Q, R)];
|
||||
//
|
||||
// OccupiedHex->bFree = false;
|
||||
// OccupiedHex->MapObject = this;
|
||||
//}
|
62
MapObject.h
Normal file
62
MapObject.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "HexVector.h"
|
||||
#include "MapObject.generated.h"
|
||||
|
||||
class USceneComponent;
|
||||
class UStaticMeshComponent;
|
||||
class AAdventureMap;
|
||||
|
||||
UCLASS()
|
||||
class FRAY_API AMapObject : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Sets default values for this actor's properties
|
||||
AMapObject();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Config")
|
||||
AAdventureMap* MapRef;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Config")
|
||||
USceneComponent* SceneComponent;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Config")
|
||||
UStaticMeshComponent* OrientHexMesh;
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Config")
|
||||
bool bCollectable;
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Config")
|
||||
bool bActivatable;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Generation")
|
||||
int32 ID;
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Generation")
|
||||
class AHexTile* Origin; // very important
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Generation")
|
||||
bool bPlaced;
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Generation")
|
||||
TArray<FHexVector> Occupying;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Runtime")
|
||||
AController* FlaggedBy;
|
||||
|
||||
UFUNCTION()
|
||||
virtual void Touch();
|
||||
UFUNCTION()
|
||||
virtual void Activate();
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void Occupy();
|
||||
|
||||
};
|
90
MovementArrow.cpp
Normal file
90
MovementArrow.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "MovementArrow.h"
|
||||
#include "AdventureMap.h"
|
||||
|
||||
// Sets default values
|
||||
AMovementArrow::AMovementArrow()
|
||||
{
|
||||
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
|
||||
RootComponent = SceneComponent;
|
||||
MeshStraight = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Straight"));
|
||||
MeshRight = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Right"));
|
||||
MeshRightSharp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RightSharp"));
|
||||
MeshLeftSharp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("LeftSharp"));
|
||||
MeshLeft = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Left"));
|
||||
MeshVariants.Add(MeshStraight);
|
||||
MeshVariants.Add(MeshRight);
|
||||
MeshVariants.Add(MeshRightSharp);
|
||||
MeshVariants.Add(MeshLeftSharp);
|
||||
MeshVariants.Add(MeshLeft);
|
||||
|
||||
for (UStaticMeshComponent* Mesh : MeshVariants) {
|
||||
Mesh->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
|
||||
Mesh->ToggleVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
void AMovementArrow::SetVariant(FHexVector InVector, FHexVector OutVector) {
|
||||
int32 InVectorIndex = MapRef->UnitVectors.Find(InVector);
|
||||
int32 OutVectorIndex = MapRef->UnitVectors.Find(OutVector);
|
||||
int32 VariantIndex;
|
||||
if (InVectorIndex == 0) {
|
||||
if (OutVectorIndex == 0) { VariantIndex = 0; }
|
||||
if (OutVectorIndex == 1) { VariantIndex = 1; }
|
||||
if (OutVectorIndex == 2) { VariantIndex = 2; }
|
||||
if (OutVectorIndex == 4) { VariantIndex = 3; }
|
||||
if (OutVectorIndex == 5) { VariantIndex = 4; }
|
||||
}
|
||||
if (InVectorIndex == 1) {
|
||||
if (OutVectorIndex == 0) { VariantIndex = 4; }
|
||||
if (OutVectorIndex == 1) { VariantIndex = 0; }
|
||||
if (OutVectorIndex == 2) { VariantIndex = 1; }
|
||||
if (OutVectorIndex == 3) { VariantIndex = 2; }
|
||||
if (OutVectorIndex == 5) { VariantIndex = 3; }
|
||||
}
|
||||
if (InVectorIndex == 2) {
|
||||
if (OutVectorIndex == 0) { VariantIndex = 3; }
|
||||
if (OutVectorIndex == 1) { VariantIndex = 4; }
|
||||
if (OutVectorIndex == 2) { VariantIndex = 0; }
|
||||
if (OutVectorIndex == 3) { VariantIndex = 1; }
|
||||
if (OutVectorIndex == 4) { VariantIndex = 2; }
|
||||
}
|
||||
if (InVectorIndex == 3) {
|
||||
if (OutVectorIndex == 1) { VariantIndex = 3; }
|
||||
if (OutVectorIndex == 2) { VariantIndex = 4; }
|
||||
if (OutVectorIndex == 3) { VariantIndex = 0; }
|
||||
if (OutVectorIndex == 4) { VariantIndex = 1; }
|
||||
if (OutVectorIndex == 5) { VariantIndex = 2; }
|
||||
}
|
||||
if (InVectorIndex == 4) {
|
||||
if (OutVectorIndex == 0) { VariantIndex = 2; }
|
||||
if (OutVectorIndex == 2) { VariantIndex = 3; }
|
||||
if (OutVectorIndex == 3) { VariantIndex = 4; }
|
||||
if (OutVectorIndex == 4) { VariantIndex = 0; }
|
||||
if (OutVectorIndex == 5) { VariantIndex = 1; }
|
||||
}
|
||||
if (InVectorIndex == 5) {
|
||||
if (OutVectorIndex == 0) { VariantIndex = 1; }
|
||||
if (OutVectorIndex == 1) { VariantIndex = 2; }
|
||||
if (OutVectorIndex == 3) { VariantIndex = 3; }
|
||||
if (OutVectorIndex == 4) { VariantIndex = 4; }
|
||||
if (OutVectorIndex == 5) { VariantIndex = 0; }
|
||||
}
|
||||
SceneComponent->SetRelativeRotation(FRotator(0, InVectorIndex * 60.f, 0));
|
||||
MeshVariants[VariantIndex]->ToggleVisibility();
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void AMovementArrow::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void AMovementArrow::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
}
|
48
MovementArrow.h
Normal file
48
MovementArrow.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "HexVector.h"
|
||||
#include "MovementArrow.generated.h"
|
||||
|
||||
class USceneComponent;
|
||||
class UStaticMeshComponent;
|
||||
class AAdventureMap;
|
||||
|
||||
UCLASS()
|
||||
class FRAY_API AMovementArrow : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Sets default values for this actor's properties
|
||||
AMovementArrow();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Config")
|
||||
AAdventureMap* MapRef;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Config")
|
||||
USceneComponent* SceneComponent;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Variant")
|
||||
UStaticMeshComponent* MeshStraight;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Variant")
|
||||
UStaticMeshComponent* MeshRight;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Variant")
|
||||
UStaticMeshComponent* MeshRightSharp;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Variant")
|
||||
UStaticMeshComponent* MeshLeftSharp;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Variant")
|
||||
UStaticMeshComponent* MeshLeft;
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Variant")
|
||||
TArray<UStaticMeshComponent*> MeshVariants;
|
||||
UFUNCTION(BlueprintCallable, Category = "Variant")
|
||||
void SetVariant(FHexVector InVector, FHexVector OutVector);
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
};
|
27
StarFog.cpp
Normal file
27
StarFog.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "StarFog.h"
|
||||
|
||||
// Sets default values
|
||||
AStarFog::AStarFog()
|
||||
{
|
||||
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void AStarFog::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void AStarFog::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
}
|
||||
|
31
StarFog.h
Normal file
31
StarFog.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "StarFog.generated.h"
|
||||
|
||||
class AHexTile;
|
||||
|
||||
UCLASS()
|
||||
class FRAY_API AStarFog : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Sets default values for this actor's properties
|
||||
AStarFog();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
|
||||
AHexTile* CoveredHex;
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
};
|
Reference in New Issue
Block a user