diff --git a/AdventureCameraPawn.cpp b/AdventureCameraPawn.cpp index 039ec6e..97f94db 100644 --- a/AdventureCameraPawn.cpp +++ b/AdventureCameraPawn.cpp @@ -18,10 +18,11 @@ 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; - ESASize = .01; BaseScrollSpeed = 20; ScrollAccelleration = BaseScrollSpeed * 3; + ESASize = .01; + ESAMaxBoundSlope = 1 / (1 - (1-ESASize)); ESAMaxBoundIntercept = 1 - ESAMaxBoundSlope; @@ -176,7 +177,6 @@ void AAdventureCameraPawn::EdgeScrollVert(float AxisValue) SpeedY = AxisValue * ScrollAccelleration; AddActorLocalOffset(FVector(0, -SpeedY, 0)); } - } } diff --git a/AdventureCharacter.cpp b/AdventureCharacter.cpp index 28192a0..ac47c3b 100644 --- a/AdventureCharacter.cpp +++ b/AdventureCharacter.cpp @@ -31,5 +31,4 @@ void AAdventureCharacter::Tick(float DeltaTime) void AAdventureCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); - } \ No newline at end of file diff --git a/AdventureMap.cpp b/AdventureMap.cpp index 23f28df..0742030 100644 --- a/AdventureMap.cpp +++ b/AdventureMap.cpp @@ -36,7 +36,6 @@ void AAdventureMap::MakeGrid() for (int r = 1; r <= GridSize; r++) { float XOffset = 0.f; - if (r % 2 != 0) { if (r > 1) { QOffset--; } } else { XOffset = HexWidth / 2; } @@ -45,23 +44,19 @@ void AAdventureMap::MakeGrid() NextHexAt.Y = TileSize * 1.5f * r; NextHexAt.Z = 0.f; FTransform SpawnTransform = FTransform(NextHexAt); - AHexTile* Tile = World->SpawnActor(BaseTileClass, SpawnTransform); Grid.Add(Tile); - Tile->Q = q - 1 + QOffset; Tile->R = r - 1; } } - 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) { /* @@ -78,50 +73,36 @@ AHexTile* AAdventureMap::RandomHex() return Grid[RandHex]; } -/* -* Add two TArray> members containing the Cardinal Directions - (one for immediate neighbors, one for diagonals) - { fill them in AAdventureMap::AAdventureMap } - -* This function instead returns - TMap -*/ TArray AAdventureMap::Neighbors(AHexTile* OfHex, bool bFreeOnly = false) { TArray Results; for (auto& V : NeighborUnitVectors) { int32 I = GridIndex(OfHex->Q + V.Q, OfHex->R + V.R); if (Grid.IsValidIndex(I)) { - AHexTile* R = Grid[I]; - Results.Add(Grid[I]); - if (bFreeOnly && !R->bFree) { Results.Remove(R); } + AHexTile* H = Grid[I]; + if (bFreeOnly && !H->bFree) { continue; } + if (H->Distance(OfHex) == 1) { Results.Add(H); } } } - for (auto& R : Results) { - if (bFreeOnly && !R->bFree) { Results.Remove(R); } - } return Results; } -TArray AAdventureMap::FreeDiags(AHexTile* OfHex) +TArray AAdventureMap::FreeDiagonals(AHexTile* OfHex) { TArray Results; for (auto& V : DiagonalUnitVectors) { int32 I = GridIndex(OfHex->Q + V.Q, OfHex->R + V.R); if (!Grid.IsValidIndex(I)) { continue; } - // if (!bFreeOnly) { if (Grid[I]->Distance(OfHex) == 1) { Results.Add(Grid[I]); } } else { bool bReachable = true; - for (auto& PotentialBlock : Neighbors(OfHex)) { + for (AHexTile* PotentialBlock : Neighbors(OfHex)) { if (PotentialBlock->Distance(Grid[I]) != 1) { continue; } if (!PotentialBlock->bFree) { bReachable = false; break; } } - if (bReachable) { - Results.Add(Grid[I]); - } + if (bReachable) { Results.Add(Grid[I]); } } } return Results; @@ -162,7 +143,7 @@ TArray AAdventureMap::FindPathAStar(AHexTile* Start, AHexTile* Goal, AHexTile* Candidate = ToExamine[0]; ToExamine.Remove(Candidate); // try for Hex with lower estimatet (F)cost - for (auto& t : ToExamine) { + for (AHexTile* t : ToExamine) { t->FCost = t->GCost + t->HCost; if (t->FCost < Candidate->FCost || t->FCost == Candidate->FCost && t->HCost < Candidate->HCost) { Candidate = t; } } @@ -173,42 +154,42 @@ TArray AAdventureMap::FindPathAStar(AHexTile* Start, AHexTile* Goal, // expand frontier & adjust path data for (AHexTile* Neighbor : Neighbors(Candidate, true)) { - if (Neighbor->Distance(Candidate) > 1) { continue; } + if (!Neighbor->bFree) { continue; } if (Processed.Contains(Neighbor)) { continue; } bool bInToExamine = ToExamine.Contains(Neighbor); - float NewGCost = Candidate->GCost + Neighbor->MoveCost * 10.f; + float NewGCost = Candidate->GCost + Neighbor->MoveCost; if (NewGCost < Neighbor->GCost || !bInToExamine) { Neighbor->GCost = NewGCost; Neighbor->CameFrom = Candidate; // chain + Neighbor->bDiagMove = false; if (!bInToExamine) { - Neighbor->HCost = Neighbor->Distance(Goal) * 10.f; + Neighbor->HCost = Neighbor->Distance(Goal); ToExamine.Add(Neighbor); - } - } + } } } - if (bDiags) { // right now the heuristic for HCost (Distance func) does NOT take diagonals into account - for (AHexTile* Diag : FreeDiags(Candidate)) { - if (Diag->Distance(Candidate) > 2) { continue; } + /* + if (bDiags) { + for (AHexTile* Diag : FreeDiagonals(Candidate)) { if (!Diag->bFree) { continue; } if (Processed.Contains(Diag)) { continue; } bool bInToExamine = ToExamine.Contains(Diag); - float NewGCost = Candidate->GCost + Diag->MoveCost * 10.f; + float NewGCost = Candidate->GCost + Diag->MoveCost; if (NewGCost < Diag->GCost || !bInToExamine) { Diag->GCost = NewGCost; Diag->CameFrom = Candidate; // chain + Diag->bDiagMove = true; if (!bInToExamine) { - Diag->HCost = Diag->Distance(Goal) * 10.f; + Diag->HCost = Diag->Distance(Goal); ToExamine.Add(Diag); - } - } + } } } - } + }*/ } TArray Path; if (!IsValid(Goal->CameFrom)) { return Path; } @@ -218,5 +199,96 @@ TArray AAdventureMap::FindPathAStar(AHexTile* Start, AHexTile* Goal, iPathNode = iPathNode->CameFrom; } Algo::Reverse(Path); + + if (bDiags) { + Path = ShortcutAStar(Path); + } + return Path; +} + + +TArray AAdventureMap::ShortcutAStar(TArray Path) +{ + TArray Shortcut; + int32 Len = Path.Num(); + AHexTile* Milestone = Path[0]; + int32 BeforeBend; + int32 AfterBend; + int32 HexIter = 1; + FHexVector pDir; + FHexVector DirA; + FHexVector DirB; + AHexTile* Current; + + while (Milestone != Path[Len - 1]) { + // find Milestone (i.e. end of first curve) & determine curve data + BeforeBend = 1; + for (HexIter; HexIter < Len; HexIter++) { + pDir = FHexVector(Path[HexIter], Path[HexIter - 1]); + DirA = FHexVector(Path[HexIter + 1], Path[HexIter]); + if (DirA == pDir) { BeforeBend++; } + else { break; } + } + AfterBend = 1; + for (HexIter; HexIter < Len; HexIter++) { + pDir = FHexVector(Path[HexIter], Path[HexIter - 1]); + DirB = FHexVector(Path[HexIter + 1], Path[HexIter]); + if (DirB == pDir) { AfterBend++; } + else { break; } + } + FHexVector Diag = UnitDiagFromUnitNB(DirA, DirB); // (exact diagonal) cardinal direction for shortcut + TArray WorkingSegment; + for (int32 i = Path.Find(Milestone); i < HexIter; i++) { WorkingSegment.Add(Path[i]); } + Milestone = WorkingSegment.Last(); + Current = WorkingSegment[0]; + bool bFirstDiagTaken = false; + TArray NewSegment; // ideally the entire shortcut (ends at bBlock, whence we continue by A*) + + // link from Current to Milestone + for (int32 i = 0; i < BeforeBend; i++) { + Current = WorkingSegment[i]; + AHexTile* NewCandidate = Grid[GridIndex(Current->Q + Diag.Q, Current->R + Diag.R)]; + if (!DiagIsReachable(Current, Diag) || !NewCandidate->bFree) { + if (bFirstDiagTaken) { break; } + NewSegment.Add(Current); + continue; + } + NewSegment.Add(NewCandidate); + bFirstDiagTaken = true; + } + + // Check how much remains until we reach milestone and + // Connect the rest recursively via A* (with shortcuts) + // Consider whether the resulting path really is shorter + + Shortcut.Append(NewSegment); + } + + // Construct shortcut + 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; } + AHexTile* HexA = Grid[GridIndex(InStart->Q + BlockA.Q, InStart->R + BlockA.R)]; + AHexTile* HexB = Grid[GridIndex(InStart->Q + BlockB.Q, InStart->R + BlockB.R)]; + return (HexA->bFree && HexB->bFree); } \ No newline at end of file diff --git a/AdventureMap.h b/AdventureMap.h index 2672d97..3121fae 100644 --- a/AdventureMap.h +++ b/AdventureMap.h @@ -26,7 +26,7 @@ public: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config") TSubclassOf BaseTileClass; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config") - int32 GridSize = 100; // squared is the number of Tiles + int32 GridSize = 100; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config") int32 TileSize = 100; @@ -44,43 +44,50 @@ public: // Cardinal direction vectors UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag - FHexVector N = FHexVector(1, -2); + FHexVector N = FHexVector(1, -2); // UPROPERTY(BlueprintReadOnly, VisibleAnywhere) FHexVector NNE = FHexVector(1, -1); UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag - FHexVector ENE = FHexVector(2, -1); + FHexVector ENE = FHexVector(2, -1); // UPROPERTY(BlueprintReadOnly, VisibleAnywhere) FHexVector E = FHexVector(1, 0); UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag - FHexVector ESE = FHexVector(1, 1); + FHexVector ESE = FHexVector(1, 1); // UPROPERTY(BlueprintReadOnly, VisibleAnywhere) FHexVector SSE = FHexVector(0, 1); UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag - FHexVector S = FHexVector(-1, 2); + FHexVector S = FHexVector(-1, 2); // UPROPERTY(BlueprintReadOnly, VisibleAnywhere) FHexVector SSW = FHexVector(-1, 1); UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag - FHexVector WSW = FHexVector(-2, 1); + FHexVector WSW = FHexVector(-2, 1); // UPROPERTY(BlueprintReadOnly, VisibleAnywhere) FHexVector W = FHexVector(-1, 0); UPROPERTY(BlueprintReadOnly, VisibleAnywhere) //diag - FHexVector WNW = FHexVector(-1, -1); + FHexVector WNW = FHexVector(-1, -1); // UPROPERTY(BlueprintReadOnly, VisibleAnywhere) FHexVector NNW = FHexVector(0, -1); - UPROPERTY(BlueprintReadOnly, VisibleAnywhere) TArray NeighborUnitVectors; UPROPERTY(BlueprintReadOnly, VisibleAnywhere) TArray DiagonalUnitVectors; + UFUNCTION(BlueprintCallable, Category = "Utility") + FHexVector UnitDiagFromUnitNB(FHexVector InVecA, FHexVector InVecB); + UFUNCTION(BlueprintCallable, Category = "Utility") + bool DiagIsReachable(AHexTile* InStart, FHexVector InDiagUnitVec); UFUNCTION(BlueprintCallable, Category = "Runtime") TArray Neighbors(AHexTile* OfHex, bool bFreeOnly); UFUNCTION(BlueprintCallable, Category = "Runtime") - TArray FreeDiags(AHexTile* OfHex); + TArray FreeDiagonals(AHexTile* OfHex); UFUNCTION(BlueprintCallable, Category = "Runtime") TSet BreadthFirstSearch(AHexTile* Start, int32 Radius); UFUNCTION(BlueprintCallable, Category = "Runtime") TArray FindPathAStar(AHexTile* Start, AHexTile* Goal, bool bDiags); + UFUNCTION(BlueprintCallable, Category = "Runtime") + TArray ShortcutAStar(TArray Path); + +// considering a MapObjectManager class or moving pathfinding & search to PlayerController UPROPERTY(BlueprintReadWrite, EditAnywhere) TMap MapObjects; diff --git a/AdventurePlayerController.cpp b/AdventurePlayerController.cpp index ea74ded..f344265 100644 --- a/AdventurePlayerController.cpp +++ b/AdventurePlayerController.cpp @@ -45,10 +45,12 @@ void AAdventurePlayerController::LeftClick() if (bInPlacementMode) { PlaceObject(PlaceObjClass, HoveredHex); } } -TArray AAdventurePlayerController::Vision() +TArray AAdventurePlayerController::Vision(int32 Radius) { TArray Results; - TSet Visible = MapRef->BreadthFirstSearch(CurrentHex, 4); + TSet Visible; + if (CurrentHex->bDiagMove) { Radius = FMath::FloorToInt(float(Radius) * (2.f / 3.f)); } + Visible = MapRef->BreadthFirstSearch(CurrentHex, Radius); for (auto& Hex : Visible) { if (ExploredHexes.Contains(Hex)) { continue; } Results.Add(Hex); @@ -60,31 +62,25 @@ TArray AAdventurePlayerController::Vision() void AAdventurePlayerController::TogglePlacing() { bInPlacementMode = !bInPlacementMode; - if (bInPlacementMode) { - PlaceObj = World->SpawnActor(PlaceObjClass, FTransform()); - } + if (bInPlacementMode) { PlaceObj = World->SpawnActor(PlaceObjClass, FTransform()); } else { if (IsValid(PlaceObj)) { PlaceObj->Destroy(); } } } void AAdventurePlayerController::FitOnGrid(AMapObject* MapObject) { if (!IsValid(HoveredHex)) { return; } - if (HoveredHex->bFree) { - MapObject->SetActorLocation(FVector(HoveredHex->GetActorLocation())); - } + if (HoveredHex->bFree) { MapObject->SetActorLocation(FVector(HoveredHex->GetActorLocation())); } } // called from BP; generally takes the Hex under the player cursor as argument void AAdventurePlayerController::PlaceObject(TSubclassOf MapObjClass, AHexTile* OnHex) { - // spawn this Actor at World location of Origin Hex; AMapObject* SpawnedObj = World->SpawnActor(MapObjClass, FTransform(OnHex->GetActorTransform().GetLocation())); SpawnedObj->Origin = OnHex; + OnHex->bFree = false; + SpawnedObj->Occupy(); - // set Hexes to bOccupied according to BlockVectors; - OnHex->bFree = false; // exact Hexes are eventually to be determined by MapObjectClass's BlockingVectors - - MapRef->MapObjects.Add(OnHex, SpawnedObj); // maybe this as well + MapRef->MapObjects.Add(OnHex, SpawnedObj); MapRef->IncID++; SpawnedObj->ID = MapRef->IncID; MapRef->MapObjectsByID.Add(MapRef->IncID, SpawnedObj); diff --git a/AdventurePlayerController.h b/AdventurePlayerController.h index b42e5d3..05ad914 100644 --- a/AdventurePlayerController.h +++ b/AdventurePlayerController.h @@ -42,9 +42,9 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite) TSet ExploredHexes; UPROPERTY(EditAnywhere, BlueprintReadWrite) - int32 VisionRadius = 7; + int32 VisionRadius = 6; UFUNCTION(BlueprintCallable) - TArray Vision(); + TArray Vision(int32 Radius); protected: virtual void BeginPlay() override; diff --git a/HexTile.cpp b/HexTile.cpp index a9b6f62..a057f64 100644 --- a/HexTile.cpp +++ b/HexTile.cpp @@ -10,40 +10,26 @@ AHexTile::AHexTile() { TileSize = 100.f; - RootComponent = CreateDefaultSubobject(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; } \ No newline at end of file diff --git a/HexTile.h b/HexTile.h index 5bbce5f..b8ca315 100644 --- a/HexTile.h +++ b/HexTile.h @@ -45,10 +45,14 @@ public: int32 Distance(AHexTile* ToHex); // Pathfinding - UPROPERTY(BlueprintReadWrite, Category = "Movement") + UPROPERTY(BlueprintReadWrite) float MoveCost = 10; - UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category = "Movement") + UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category = "Runtime") AHexTile* CameFrom; + UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category = "Runtime") + AHexTile* LeadsTo; + UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category = "Runtime") + bool bDiagMove = false; UPROPERTY() float FCost; UPROPERTY() @@ -59,6 +63,10 @@ public: // MapObject Placement UPROPERTY(BlueprintReadWrite, VisibleAnywhere) bool bFree = true; + UPROPERTY(BlueprintReadWrite, EditAnywhere) + bool bTouchable = false; + UPROPERTY(BlueprintReadWrite, EditAnywhere) + bool bSteptivatable = false; FORCEINLINE bool operator == (const AHexTile &Other) { diff --git a/HexVector.h b/HexVector.h new file mode 100644 index 0000000..5c2ff64 --- /dev/null +++ b/HexVector.h @@ -0,0 +1,58 @@ +#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; + + TArray Related; +}; + +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; } +} \ No newline at end of file diff --git a/MapObject.cpp b/MapObject.cpp new file mode 100644 index 0000000..eaed6ed --- /dev/null +++ b/MapObject.cpp @@ -0,0 +1,46 @@ +// 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(TEXT("Scene")); + RootComponent = SceneComponent; + OrientHexMesh = CreateDefaultSubobject(TEXT("Orient")); + OrientHexMesh->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform); +} + +// Called when the game starts or when spawned +void AMapObject::BeginPlay() +{ + Super::BeginPlay(); + Occupy(); +} + +// Called every frame +void AMapObject::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); +} + +void AMapObject::Touch() +{ +} + +void AMapObject::Activate() +{ +} + +void AMapObject::Occupy() +{ + for (auto& V : Occupying) { + MapRef->Grid[MapRef->GridIndex(Origin->Q + V.Q, Origin->R + V.R)]->bFree = false; + } +} diff --git a/MapObject.h b/MapObject.h new file mode 100644 index 0000000..63b3b65 --- /dev/null +++ b/MapObject.h @@ -0,0 +1,59 @@ +// 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, VisibleAnywhere, Category = "Config") + bool bCollectable; + UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Config") + bool bActivatable; + + UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Generation") + int32 ID; + UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Generation") + class AHexTile* Origin; // very important + UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Generation") + TArray 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; + + void Occupy(); + +};