Space Plunder
Loading...
Searching...
No Matches
AProceduralDungeonBuilder Class Reference

#include <ProceduralDungeonBuilder.h>

Inheritance diagram for AProceduralDungeonBuilder:

Public Member Functions

 AProceduralDungeonBuilder ()
 

Protected Member Functions

virtual void BeginPlay () override
 
virtual void OnConstruction (const FTransform &Transform) override
 
void CreateDungeonInEditor ()
 
void DestroyDungeonInEditor ()
 
void HideAllRoomRoofs ()
 
void CreateDungeon ()
 
void OnDungeonComplete (const int32 NumOfRooms)
 
void OnDoorsSpawned (const int32 NumOfDoors)
 
void OnAISpawned (const int32 NumOfPawns)
 
void Multicast_DungeonComplete (int32 NumRooms)
 
FRandomStream & GetRandomStream () const
 
bool IsOverlapping (const FBox &CandidateBox)
 
bool GetIsValidRoomConnection (const EDungeonRoomType ParentType, const EDungeonRoomType CandidateType) const
 
UMaterialInstanceDynamic * GetMaterialInstance () const
 
void SpawnStartingRoom ()
 
void SpawnAllRooms ()
 
void CreateDynamicMaterials ()
 
void SpawnNextRoom ()
 
void ContinueSpawnNextRoom ()
 
void SetInitialValues ()
 
void SpawnSpecialRoom ()
 
void ScheduleSpawn (const FTimerDelegate::TMethodPtr< AProceduralDungeonBuilder > SpawnMethod)
 
void AddAISpawnPointsToList (const USceneComponent *AIRootComponent)
 
void CheckExitsForJoiningRooms ()
 
void CloseHoles ()
 
void SpawnDoorAtLocation ()
 
void SpawnAIAtLocation ()
 
void SetRoomsReady () const
 
void DungeonComplete ()
 

Protected Attributes

FDungeonSpawns RoomTypes
 
int32 StartingRoomNumber = 0
 
int32 NumberOfRoomsToSpawn = 50
 
bool bUseRandomNumberOfRooms = false
 
int32 MinNumberOfRoomsToSpawn = 2
 
TSubclassOf< AActor > RoomChecker = nullptr
 
bool bApplyDynamicMaterial = true
 
UMaterialInterface * RoomMaterial = nullptr
 
class UDataTable * MaterialDataTable = nullptr
 
bool bCheckRoomExitCount = false
 
int32 CheckRoomExitCountMin = 3
 
bool bCheckRoomTypes = true
 
bool bGetClosestExit = false
 
bool bRandomGetClosestExit = false
 
float RandomClosesExitWeight = 0.5f
 
bool bUseRandomSeed = true
 
int32 Seed = 0
 
TSubclassOf< AActor > WallFill = nullptr
 
bool bFillWithDeadEndRooms = false
 
bool bSpawnDoors = true
 
bool bLimitDoors = true
 
int32 DoorLimit = 10
 
TArray< TSubclassOf< AActor > > DoorTypes
 
TArray< int32 > DoorWeights
 
bool bCreateOnBeginPlay = true
 
bool bUseGameModeStream = true
 
bool bCheckForJoiningRooms = true
 
int32 AIToSpawn = 10
 
TArray< TSubclassOf< AActor > > AITypes
 
bool bComplete = false
 
TArray< USceneComponent * > AvailableExits
 
TArray< USceneComponent * > DoorLocations
 
TArray< USceneComponent * > ExitsToFill
 
USceneComponent * SelectedExit = nullptr
 
AActor * LastSpawnedRoom = nullptr
 
TArray< UPrimitiveComponent * > OverlappedComponents
 
TArray< AActor * > DungeonActors
 
TArray< TSubclassOf< AActor > > SpecialRoomTypeClasses
 
UMaterialInstanceDynamic * RoomMaterialInstance = nullptr
 
TArray< FBox > PlacedRoomBounds
 
USceneComponent * SelectedAISpawn = nullptr
 
USceneComponent * SelectedDoorSpawn = nullptr
 
TArray< USceneComponent * > AISpawns
 
bool bUsingGameModeSteam = false
 
TArray< USceneComponent * > AISpawnsSelected
 
TArray< USceneComponent * > AISpawnsFailed
 
TArray< USceneComponent * > DoorSpawnsSelected
 
TArray< USceneComponent * > DoorSpawnsFailed
 

Private Member Functions

void OnRoomsComplete ()
 
void CheckRoomAttemptsNumber ()
 
void SetSeed ()
 
void SetNumberOfRooms ()
 
bool GetShouldStopSpawningRooms () const
 
bool GetShouldSpawnSpecialRoom () const
 
USceneComponent * GetNextExit ()
 
UClass * GetNewRoomClass () const
 
UClass * GetStartingRoomClass ()
 
UClass * GetSpecialRoomClass () const
 
UClass * GetDeadEndRoomClass () const
 
TArray< FDungeonSpawnRoomGetRoomsOfTypeBP (const TArray< EDungeonRoomType > &FilterTypes, const bool bInverseSelection=false) const
 
TArray< FDungeonSpawnRoomGetRoomsOfType (const TArray< EDungeonRoomType > &FilterTypes, const bool bInverseSelection=false) const
 
TArray< FDungeonSpawnRoomGetRoomsOfType (const EDungeonRoomType FilterType, const bool bInverseSelection=false) const
 
TArray< FDungeonSpawnRoomGetRoomsByExits () const
 
void RemoveExitsByDistance (TArray< USceneComponent * > &ExitsA, TArray< USceneComponent * > &ExitsB) const
 
bool SetDungeonValues ()
 
void LogDebugError (const FString &Message) const
 
void LogDebugWarning (const FString &Message) const
 
void LogDebugMessage (const FString &Message, const bool bWarning=false, const bool bError=false) const
 

Private Attributes

FActorSpawnParameters SpawnParams
 
int32 RoomsSpawned = 0
 
int32 AttemptChecker = 0
 
int32 StartingNumberOfRoomsToSpawn = 0
 
int32 TotalNumberOfRoomsToSpawn = 0
 
FDungeonSpawns StartingRoomTypes
 
int32 StartingAIToSpawn = 0
 
int32 AISpawned = 0
 
int32 DoorsSpawned = 0
 
bool bCreatedInEditor = false
 
FRandomStream RandomStream
 
FRandomStream * RandomStreamPtr = nullptr
 
FRandomStream NullRandomStream
 
TArray< IDungeonRoom * > AllDungeonRooms
 
float ExitLocationDistanceOverlap = 0.1f
 
bool bDeleteExitBeforeSpawn = true
 
int32 RoomAttemptsBeforeFail = 5
 
int32 RoomAttemptsMathMultiplier = 5
 
bool bHasInvalidClass = false
 
bool bHideRoomRoofs = false
 
bool bGiveRoomsRandomStream = false
 
bool bAddStartingExit = false
 
bool bDebuggingMode = true
 
bool bDrawFailedExits = false
 
bool bLogDungeonSummary = true
 
bool bLogDungeonSteps = false
 
bool bResetRoomTypesOnComplete = false
 
bool bDelayEachRoomBuild = false
 
bool bDelayEachAISpawn = false
 
bool bDelayEachDoorSpawn = false
 
float BuildDelayTime = 0.1f
 
FTimerHandle BuildDelayHandle
 

Constructor & Destructor Documentation

◆ AProceduralDungeonBuilder()

AProceduralDungeonBuilder::AProceduralDungeonBuilder ( )
29{
30 PrimaryActorTick.bCanEverTick = false;
31 SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
32}
FActorSpawnParameters SpawnParams
Definition ProceduralDungeonBuilder.h:327

Member Function Documentation

◆ AddAISpawnPointsToList()

void AProceduralDungeonBuilder::AddAISpawnPointsToList ( const USceneComponent * AIRootComponent)
protected

Adds any overlapping components to a List

630{
631 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::AddAISpawnPointsToList);
632 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
633 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
634 if(AIRootComponent == nullptr){return;}
635 TArray<USceneComponent*> AISpawnComponents;
636 AIRootComponent->GetChildrenComponents(false, AISpawnComponents);
637 AISpawns.Append(AISpawnComponents);
638}
TArray< USceneComponent * > AISpawns
Definition ProceduralDungeonBuilder.h:256
void AddAISpawnPointsToList(const USceneComponent *AIRootComponent)
Definition ProceduralDungeonBuilder.cpp:629

◆ BeginPlay()

void AProceduralDungeonBuilder::BeginPlay ( )
overrideprotectedvirtual
35{
36 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
37 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
38 Super::BeginPlay();
40 {
42 }
43}
bool bCreateOnBeginPlay
Definition ProceduralDungeonBuilder.h:201
void CreateDungeon()
Definition ProceduralDungeonBuilder.cpp:101

◆ CheckExitsForJoiningRooms()

void AProceduralDungeonBuilder::CheckExitsForJoiningRooms ( )
protected

Check exits after the generator is complete, to see if they're next to Rooms

641{
642 if(bLogDungeonSteps){LogDebugWarning("CheckExitsForJoiningRooms");}
643 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::CheckExitsForJoiningRooms);
644 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
645 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
646 if(AvailableExits.IsEmpty()){return;}
647 // Iterate over the array from the start to find duplicates by distance
651}
TArray< USceneComponent * > AvailableExits
Definition ProceduralDungeonBuilder.h:223
bool bLogDungeonSteps
Definition ProceduralDungeonBuilder.h:410
void LogDebugWarning(const FString &Message) const
Definition ProceduralDungeonBuilder.cpp:1348
void CheckExitsForJoiningRooms()
Definition ProceduralDungeonBuilder.cpp:640
void RemoveExitsByDistance(TArray< USceneComponent * > &ExitsA, TArray< USceneComponent * > &ExitsB) const
Definition ProceduralDungeonBuilder.cpp:653
TArray< USceneComponent * > ExitsToFill
Definition ProceduralDungeonBuilder.h:228

◆ CheckRoomAttemptsNumber()

void AProceduralDungeonBuilder::CheckRoomAttemptsNumber ( )
private

Checks that room attempts number hasn't been incorrectly input

923{
924 if(bLogDungeonSteps){LogDebugWarning("Check Room Attempts Number");}
926 {
928 }
930 {
932 }
933}
int32 RoomAttemptsBeforeFail
Definition ProceduralDungeonBuilder.h:384

◆ CloseHoles()

void AProceduralDungeonBuilder::CloseHoles ( )
protected

Closes empty exits after the generator is complete

684{
685 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::CloseHoles);
686 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
687 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
688 if(bLogDungeonSteps){LogDebugWarning("CloseHoles");}
689 if(AvailableExits.IsEmpty() && ExitsToFill.IsEmpty()){return;}
691 {
692 for(int32 i = AvailableExits.Num() - 1; i >= 0; --i)
693 {
695 UClass* SelectedRoomClass = GetDeadEndRoomClass();
696 if(SelectedRoomClass == nullptr)
697 {
698 LogDebugError("CloseHoles SelectedRoomClass nullptr.");
699 break;
700 }
701 FDungeonSpawnRoom* RoomData = RoomTypes.Find(SelectedRoomClass);
702 if(RoomData == nullptr)
703 {
704 LogDebugError(FString::Printf(TEXT("CloseHoles: No precomputed data for %s"), *SelectedRoomClass->GetName()));
705 continue;
706 }
707
708 const FTransform SpawnTransform = SelectedExit->GetComponentTransform();
709 const FBox CandidateWorldBounds = RoomData->CalculatedRoomBounds.TransformBy(SpawnTransform);
710 // 6. Check for overlap using our math (not physics overlaps).
711 if(IsOverlapping(CandidateWorldBounds))
712 {
713 LogDebugWarning("CloseHoles Candidate room would overlap an existing room.");
714 // Option: Remove this exit so we do not try it again, then try spawning a room on another exit.
716 INC_DWORD_STAT(STAT_GenerateAttempts);
719 continue;
720 }
721 AActor* DeadEndRoom = GetWorld()->SpawnActor(SelectedRoomClass, &SpawnTransform, SpawnParams);
722 const bool bValidRoom = SetDungeonValues();
723 if(bValidRoom)
724 {
725 // 8. Save the candidate room’s bounds so future rooms can check against it.
726 PlacedRoomBounds.Add(CandidateWorldBounds);
727 AttemptChecker = 0;
728 RoomData->NumberSpawned++;
729 }
730 else
731 {
732 if(DeadEndRoom != nullptr)
733 {
734 DeadEndRoom->Destroy();
735 }
736 INC_DWORD_STAT(STAT_RoomsDeleted);
738 }
739 }
740 }
741 if(WallFill == nullptr)
742 {
743 LogDebugError(FString::Printf(TEXT("CloseHoles Wall fill class INVALID")));
744 return;
745 }
746 for(const auto& Exit : AvailableExits)
747 {
748 const FTransform SpawnTransform = Exit->GetComponentTransform();
749 AActor* Wall = GetWorld()->SpawnActor(WallFill, &SpawnTransform, SpawnParams);
750 if(Wall == nullptr){LogDebugError(FString::Printf(TEXT("AvailableExits Wall Failed.. %s"), *Exit->GetReadableName()));continue;}
752 {
753 DungeonActors.Add(Wall);
754 }
755 }
756 for(const auto& Exit : ExitsToFill)
757 {
758 const FTransform SpawnTransform = Exit->GetComponentTransform();
759 AActor* Wall = GetWorld()->SpawnActor(WallFill, &SpawnTransform, SpawnParams);
760 if(Wall == nullptr){LogDebugError(FString::Printf(TEXT("ExitsToFill Wall Failed.. %s"), *Exit->GetReadableName()));continue;}
762 {
763 DungeonActors.Add(Wall);
764 }
765 }
766}
bool SetDungeonValues()
Definition ProceduralDungeonBuilder.cpp:373
TSubclassOf< AActor > WallFill
Definition ProceduralDungeonBuilder.h:185
USceneComponent * SelectedExit
Definition ProceduralDungeonBuilder.h:230
bool bCreatedInEditor
Definition ProceduralDungeonBuilder.h:356
int32 AttemptChecker
Definition ProceduralDungeonBuilder.h:332
TArray< AActor * > DungeonActors
Definition ProceduralDungeonBuilder.h:237
void LogDebugError(const FString &Message) const
Definition ProceduralDungeonBuilder.cpp:1353
UClass * GetDeadEndRoomClass() const
Definition ProceduralDungeonBuilder.cpp:1247
bool IsOverlapping(const FBox &CandidateBox)
Definition ProceduralDungeonBuilder.cpp:217
void CloseHoles()
Definition ProceduralDungeonBuilder.cpp:683
TArray< FBox > PlacedRoomBounds
Definition ProceduralDungeonBuilder.h:249
FDungeonSpawns RoomTypes
Definition ProceduralDungeonBuilder.h:131
bool bFillWithDeadEndRooms
Definition ProceduralDungeonBuilder.h:187
Definition DungeonData.h:58
FBox CalculatedRoomBounds
Definition DungeonData.h:93
int32 NumberSpawned
Definition DungeonData.h:80
FDungeonSpawnRoom * Find(const TSubclassOf< AActor > ActorClass)
Definition DungeonData.h:242

◆ ContinueSpawnNextRoom()

void AProceduralDungeonBuilder::ContinueSpawnNextRoom ( )
protected

Triggers next room function

470{
472 {
474 {
476 }
477 return;
478 }
480 {
482 }
483 else
484 {
486 }
487}
void SpawnSpecialRoom()
Definition ProceduralDungeonBuilder.cpp:535
void SpawnNextRoom()
Definition ProceduralDungeonBuilder.cpp:295
bool GetShouldStopSpawningRooms() const
Definition ProceduralDungeonBuilder.cpp:997
bool bDelayEachRoomBuild
Definition ProceduralDungeonBuilder.h:417
bool GetShouldSpawnSpecialRoom() const
Definition ProceduralDungeonBuilder.cpp:1018
void OnRoomsComplete()
Definition ProceduralDungeonBuilder.cpp:908
void ScheduleSpawn(const FTimerDelegate::TMethodPtr< AProceduralDungeonBuilder > SpawnMethod)
Definition ProceduralDungeonBuilder.cpp:617

◆ CreateDungeon()

void AProceduralDungeonBuilder::CreateDungeon ( )
protected
102{
103 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::CreateDungeon);
104 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
105 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
106 if(bLogDungeonSteps){LogDebugWarning("Create Dungeon");}
107 if(GetNetMode() != NM_Client)
108 {
109 SetSeed();
117 if(bDelayEachRoomBuild){return;}
119 {
121 }
122 CloseHoles();
127 }
128}
void CreateDynamicMaterials()
Definition ProceduralDungeonBuilder.cpp:183
void SetSeed()
Definition ProceduralDungeonBuilder.cpp:935
void SpawnDoorAtLocation()
Definition ProceduralDungeonBuilder.cpp:770
void ContinueSpawnNextRoom()
Definition ProceduralDungeonBuilder.cpp:469
void SetInitialValues()
Definition ProceduralDungeonBuilder.cpp:130
void DungeonComplete()
Definition ProceduralDungeonBuilder.cpp:864
void SpawnAIAtLocation()
Definition ProceduralDungeonBuilder.cpp:814
void SpawnAllRooms()
Definition ProceduralDungeonBuilder.cpp:138
bool bCheckForJoiningRooms
Definition ProceduralDungeonBuilder.h:207
void CheckRoomAttemptsNumber()
Definition ProceduralDungeonBuilder.cpp:922
void SetNumberOfRooms()
Definition ProceduralDungeonBuilder.cpp:986
void SetRoomsReady() const
Definition ProceduralDungeonBuilder.cpp:850
void SpawnStartingRoom()
Definition ProceduralDungeonBuilder.cpp:252

◆ CreateDungeonInEditor()

void AProceduralDungeonBuilder::CreateDungeonInEditor ( )
protected

Creates a Dungeon From the Editor

56{
58 {
60 }
61 bCreatedInEditor = true;
63}
void DestroyDungeonInEditor()
Definition ProceduralDungeonBuilder.cpp:65

◆ CreateDynamicMaterials()

void AProceduralDungeonBuilder::CreateDynamicMaterials ( )
protected
184{
185 if(bLogDungeonSteps){LogDebugWarning("CreateDynamicMaterials");}
186 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::CreateDynamicMaterials);
187 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
188 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
189 // const FSoftObjectPath UnitDataTablePath = FSoftObjectPath(TEXT("/SyntyAnimationPackage/Data/DT_SciFi_Tex.DT_SciFi_Tex"));
190 // UDataTable* DataTable = Cast<UDataTable>(UnitDataTablePath.ResolveObject());
191 // if(DataTable)
192 // {
193 // MaterialDataTable = DataTable;
194 // }
195 // DataTable = Cast<UDataTable>(UnitDataTablePath.TryLoad());
196 // if(DataTable)
197 // {
198 // MaterialDataTable = DataTable;
199 // }
200 // UE_LOG(LogDungeonBuilder, Warning, TEXT("CreateDynamicMaterials DataTable Failed"));
201
202 UMaterialInterface* CurrentMaterial = RoomMaterial;
203 RoomMaterialInstance = UMaterialInstanceDynamic::Create(CurrentMaterial, this);
204 if(RoomMaterialInstance == nullptr){LogDebugError(FString::Printf(TEXT("CreateDynamicMaterials Room Material Invalid"))); bApplyDynamicMaterial = false;return;}
205 // MaterialDataTable->FindRow<>()
206 //RoomMaterialInstance->SetTextureParameterValue();
207}
UMaterialInterface * RoomMaterial
Definition ProceduralDungeonBuilder.h:150
UMaterialInstanceDynamic * RoomMaterialInstance
Definition ProceduralDungeonBuilder.h:245
bool bApplyDynamicMaterial
Definition ProceduralDungeonBuilder.h:147

◆ DestroyDungeonInEditor()

void AProceduralDungeonBuilder::DestroyDungeonInEditor ( )
protected

Deletes the Last Dungeon From the Editor

66{
67 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::DestroyDungeonInEditor);
68 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
69 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
70 for(int32 i = DungeonActors.Num() - 1; i >= 0; --i)
71 {
72 if(DungeonActors[i] != nullptr)
73 {
74 DungeonActors[i]->Destroy();
75 }
76 }
77 DungeonActors.Empty();
78 bCreatedInEditor = false;
79 bComplete = false;
80 RoomsSpawned = 0;
81 const TArray<USceneComponent*> EmptyArray;
82 AvailableExits = EmptyArray;
86 AISpawned = 0;
87}
int32 AISpawned
Definition ProceduralDungeonBuilder.h:349
int32 AIToSpawn
Definition ProceduralDungeonBuilder.h:210
int32 StartingAIToSpawn
Definition ProceduralDungeonBuilder.h:346
int32 RoomsSpawned
Definition ProceduralDungeonBuilder.h:330
int32 StartingNumberOfRoomsToSpawn
Definition ProceduralDungeonBuilder.h:336
int32 NumberOfRoomsToSpawn
Definition ProceduralDungeonBuilder.h:138
bool bComplete
Definition ProceduralDungeonBuilder.h:220

◆ DungeonComplete()

void AProceduralDungeonBuilder::DungeonComplete ( )
protected

Sets the dungeon to complete

865{
866 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::DungeonComplete);
867 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
868 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
869 bComplete = true;
870#if WITH_EDITOR
872 {
873 GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, TEXT("DUNGEON COMPLETE"));
874 GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("Rooms: %i"), RoomsSpawned));
875 GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("AI: %i"), AISpawned));
876 GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("Seed: %i"), GetRandomStream().GetInitialSeed()));
877 GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("Doors: %i"), DoorsSpawned));
878 LogDebugError("DUNGEON COMPLETE");
879 LogDebugError(FString::Printf(TEXT("Rooms: %i"), RoomsSpawned));
880 LogDebugError(FString::Printf(TEXT("AI: %i"), AISpawned));
881 LogDebugError(FString::Printf(TEXT("Seed: %i"), GetRandomStream().GetInitialSeed()));
882 LogDebugError(FString::Printf(TEXT("Doors: %i"), DoorsSpawned));
883 }
884#endif
885 const TArray<USceneComponent*> EmptyArray;
886 AvailableExits = EmptyArray;
887 LastSpawnedRoom = nullptr;
888 SelectedExit = nullptr;
890 {
892 }
894 AttemptChecker = 0;
895 SelectedAISpawn = nullptr;
896 ExitsToFill.Empty();
897 AISpawns.Empty();
898 AllDungeonRooms.Empty();
900}
FDungeonSpawns StartingRoomTypes
Definition ProceduralDungeonBuilder.h:341
int32 DoorsSpawned
Definition ProceduralDungeonBuilder.h:351
void Multicast_DungeonComplete(int32 NumRooms)
bool bLogDungeonSummary
Definition ProceduralDungeonBuilder.h:407
USceneComponent * SelectedAISpawn
Definition ProceduralDungeonBuilder.h:252
AActor * LastSpawnedRoom
Definition ProceduralDungeonBuilder.h:233
FRandomStream & GetRandomStream() const
Definition ProceduralDungeonBuilder.cpp:972
bool bResetRoomTypesOnComplete
Definition ProceduralDungeonBuilder.h:413
TArray< IDungeonRoom * > AllDungeonRooms
Definition ProceduralDungeonBuilder.h:364

◆ GetDeadEndRoomClass()

UClass * AProceduralDungeonBuilder::GetDeadEndRoomClass ( ) const
private
1248{
1249 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetDeadEndRoomClass);
1250 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1251 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1252 // 1.Get All Rooms Except Hallways
1253 FDungeonSpawns NonHallways = FDungeonSpawns(GetRoomsOfType(EDungeonRoomType::Hallway, true));
1254 TArray<FDungeonSpawnRoom>& SelectedRooms = NonHallways.GetRooms();
1255 SelectedRooms = NonHallways.GetRoomsWithNoExits();
1256 TArray<TSubclassOf<AActor>> SelectedRoomClasses;
1257 for(auto& SelectedRoom : SelectedRooms)
1258 {
1259 if(SelectedRoom.bDisable)
1260 {
1261 continue;
1262 }
1263 //- Don't Add Types that aren't compatible
1264 if(bCheckRoomTypes)
1265 {
1266 if(SelectedExit != nullptr && SelectedExit->GetAttachParentActor() != nullptr)
1267 {
1268 UClass* ConnectingRoomClass = SelectedExit->GetAttachParentActor()->GetClass();
1269 const EDungeonRoomType ConnectingRoomType = RoomTypes.FindType(ConnectingRoomClass);
1270 const bool bValidConnection = GetIsValidRoomConnection(ConnectingRoomType, SelectedRoom.CalculatedType);
1271 if(bValidConnection == false)
1272 {
1273 continue;
1274 }
1275 }
1276 }
1277 //- Check if the Room has a limit
1278 if(SelectedRoom.bSpawnLimit)
1279 {
1280 const int32 ExistingCount = SelectedRoom.NumberSpawned;
1281 if(ExistingCount >= SelectedRoom.NumberToSpawn)
1282 {
1283 continue;
1284 }
1285 }
1286 SelectedRoomClasses.Append(SelectedRoom.GetWeightedTypes());
1287 }
1288 return UProceduralBPLib::GetRandomClassFromStream(SelectedRoomClasses, GetRandomStream());
1289}
EDungeonRoomType
Definition DungeonEnums.h:11
TArray< FDungeonSpawnRoom > GetRoomsOfType(const TArray< EDungeonRoomType > &FilterTypes, const bool bInverseSelection=false) const
Definition ProceduralDungeonBuilder.cpp:1311
bool GetIsValidRoomConnection(const EDungeonRoomType ParentType, const EDungeonRoomType CandidateType) const
bool bCheckRoomTypes
Definition ProceduralDungeonBuilder.h:163
static UClass * GetRandomClassFromStream(const TArray< TSubclassOf< AActor > > &Array, const FRandomStream &Stream)
Definition ProceduralBPLib.cpp:84
Definition DungeonData.h:169
TArray< FDungeonSpawnRoom > & GetRooms()
Definition DungeonData.h:180
EDungeonRoomType FindType(const TSubclassOf< AActor > ActorClass) const
Definition DungeonData.h:253
TArray< FDungeonSpawnRoom > GetRoomsWithNoExits() const
Definition DungeonData.h:206

◆ GetIsValidRoomConnection()

bool AProceduralDungeonBuilder::GetIsValidRoomConnection ( const EDungeonRoomType ParentType,
const EDungeonRoomType CandidateType ) const
protected

◆ GetMaterialInstance()

UMaterialInstanceDynamic * AProceduralDungeonBuilder::GetMaterialInstance ( ) const
inlineprotected
82{return RoomMaterialInstance;};

◆ GetNewRoomClass()

UClass * AProceduralDungeonBuilder::GetNewRoomClass ( ) const
private
1128{
1129 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetNewRoomClass);
1130 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1131 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1132 // 1.Get All Rooms Except Special Rooms
1133 FDungeonSpawns NonSpecialRooms = FDungeonSpawns(GetRoomsOfType(EDungeonRoomType::SpecialRoom, true));
1134 TArray<FDungeonSpawnRoom>& SelectedRooms = NonSpecialRooms.GetRooms();
1136 {
1137 const int32 ExitsLeft = AvailableExits.Num();
1138 // exclude dead end rooms.
1139 if(ExitsLeft <= CheckRoomExitCountMin && NumberOfRoomsToSpawn > CheckRoomExitCountMin)
1140 {
1141 SelectedRooms = NonSpecialRooms.GetRoomsWithExits();
1142 // if Exits are 1 or less
1143 if(ExitsLeft <= 1 && NumberOfRoomsToSpawn > CheckRoomExitCountMin)
1144 {
1145 SelectedRooms = NonSpecialRooms.GetRoomsWithNumOfExits(2);
1146 }
1147 }
1148 }
1149 TArray<TSubclassOf<AActor>> SelectedRoomClasses;
1150 for(auto& SelectedRoom : SelectedRooms)
1151 {
1152 if(SelectedRoom.bDisable)
1153 {
1154 continue;
1155 }
1156 //- Don't Add Types that aren't compatible
1157 if(bCheckRoomTypes)
1158 {
1159 if(SelectedExit != nullptr && SelectedExit->GetAttachParentActor() != nullptr)
1160 {
1161 UClass* ConnectingRoomClass = SelectedExit->GetAttachParentActor()->GetClass();
1162 const EDungeonRoomType ConnectingRoomType = RoomTypes.FindType(ConnectingRoomClass);
1163 const bool bValidConnection = GetIsValidRoomConnection(ConnectingRoomType, SelectedRoom.CalculatedType);
1164 if(bValidConnection == false)
1165 {
1166 continue;
1167 }
1168 }
1169 }
1170 //- Check if the Room has a limit
1171 if(SelectedRoom.bSpawnLimit)
1172 {
1173 const int32 ExistingCount = SelectedRoom.NumberSpawned;
1174 if(ExistingCount >= SelectedRoom.NumberToSpawn)
1175 {
1176 continue;
1177 }
1178 }
1179 SelectedRoomClasses.Append(SelectedRoom.GetWeightedTypes());
1180 }
1181 if(SelectedRoomClasses.IsEmpty()){return nullptr;}
1182 return UProceduralBPLib::GetRandomClassFromStream(SelectedRoomClasses, GetRandomStream());
1183}
bool bCheckRoomExitCount
Definition ProceduralDungeonBuilder.h:158
int32 CheckRoomExitCountMin
Definition ProceduralDungeonBuilder.h:161
UClass * GetNewRoomClass() const
Definition ProceduralDungeonBuilder.cpp:1127
TArray< FDungeonSpawnRoom > GetRoomsWithExits() const
Definition DungeonData.h:201
TArray< FDungeonSpawnRoom > GetRoomsWithNumOfExits(const int32 MinExits) const
Definition DungeonData.h:212

◆ GetNextExit()

USceneComponent * AProceduralDungeonBuilder::GetNextExit ( )
private
1092{
1093 if(bGetClosestExit)
1094 {
1096 {
1097 UKismetMathLibrary::RandomBoolWithWeightFromStream(GetRandomStream(), RandomClosesExitWeight);
1098 }
1099 const FVector OriginLocation = GetActorLocation();
1100 USceneComponent* ClosestExit = nullptr;
1101 float ClosestDistanceSquared = FLT_MAX;
1102 for (USceneComponent* Exit : AvailableExits)
1103 {
1104 if(Exit == nullptr)
1105 {
1106 continue;
1107 }
1108 // Use squared distance for performance
1109 const float DistanceSquared = FVector::DistSquared(Exit->GetComponentLocation(), OriginLocation);
1110 if (DistanceSquared < ClosestDistanceSquared)
1111 {
1112 ClosestDistanceSquared = DistanceSquared;
1113 ClosestExit = Exit;
1114 }
1115 }
1116 if(ClosestExit != nullptr)
1117 {
1118 return ClosestExit;
1119 }
1120 }
1122}
float RandomClosesExitWeight
Definition ProceduralDungeonBuilder.h:172
bool bGetClosestExit
Definition ProceduralDungeonBuilder.h:167
bool bRandomGetClosestExit
Definition ProceduralDungeonBuilder.h:170
static USceneComponent * GetRandomSceneComponentFromStream(const TArray< USceneComponent * > &Array, const FRandomStream &Stream)
Definition ProceduralBPLib.cpp:60

◆ GetRandomStream()

FRandomStream & AProceduralDungeonBuilder::GetRandomStream ( ) const
protected
973{
974 if(RandomStreamPtr != nullptr)
975 {
976 return *RandomStreamPtr;
977 }
978 if(RandomStreamPtr == nullptr)
979 {
980 UE_LOG(LogDungeonBuilder, Fatal, TEXT("AProceduralDungeonBuilder::GetRandomStream has failed"));
981 }
982 return *RandomStreamPtr;
983 // return RandomStream;
984}
FRandomStream * RandomStreamPtr
Definition ProceduralDungeonBuilder.h:360

◆ GetRoomsByExits()

TArray< FDungeonSpawnRoom > AProceduralDungeonBuilder::GetRoomsByExits ( ) const
private
1329{
1330 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetRoomsByExits);
1331 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1332 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1333 TArray<FDungeonSpawnRoom> SelectedRooms = RoomTypes.GetAllRooms();
1334 const int32 ExitsLeft = AvailableExits.Num();
1335 // exclude dead end rooms.
1336 if(ExitsLeft <= CheckRoomExitCountMin && NumberOfRoomsToSpawn > CheckRoomExitCountMin)
1337 {
1338 SelectedRooms = RoomTypes.GetRoomsWithExits();
1339 // if Exits are 1 or less
1340 if(ExitsLeft <= 1 && NumberOfRoomsToSpawn > CheckRoomExitCountMin)
1341 {
1342 SelectedRooms = RoomTypes.GetRoomsWithNumOfExits(2);
1343 }
1344 }
1345 return SelectedRooms;
1346}
TArray< FDungeonSpawnRoom > GetRoomsByExits() const
Definition ProceduralDungeonBuilder.cpp:1328
TArray< FDungeonSpawnRoom > GetAllRooms() const
Definition DungeonData.h:175

◆ GetRoomsOfType() [1/2]

TArray< FDungeonSpawnRoom > AProceduralDungeonBuilder::GetRoomsOfType ( const EDungeonRoomType FilterType,
const bool bInverseSelection = false ) const
private
1302{
1303 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetRoomsOfType);
1304 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1305 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1306 TArray<EDungeonRoomType> FilterTypes;
1307 FilterTypes.Add(FilterType);
1308 return GetRoomsOfType(FilterTypes, bInverseSelection);
1309}

◆ GetRoomsOfType() [2/2]

TArray< FDungeonSpawnRoom > AProceduralDungeonBuilder::GetRoomsOfType ( const TArray< EDungeonRoomType > & FilterTypes,
const bool bInverseSelection = false ) const
private
1312{
1313 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetRoomsOfType);
1314 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1315 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1316 TArray<FDungeonSpawnRoom> SelectedRooms = RoomTypes.GetAllRooms();
1317 const int32 RoomsLength = SelectedRooms.Num() - 1;
1318 for(int32 i = RoomsLength; i >= 0; --i)
1319 {
1320 if(FilterTypes.Contains(SelectedRooms[i].CalculatedType) == bInverseSelection)
1321 {
1322 SelectedRooms.RemoveAt(i);
1323 }
1324 }
1325 return SelectedRooms;
1326}

◆ GetRoomsOfTypeBP()

TArray< FDungeonSpawnRoom > AProceduralDungeonBuilder::GetRoomsOfTypeBP ( const TArray< EDungeonRoomType > & FilterTypes,
const bool bInverseSelection = false ) const
private
1293{
1294 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetRoomsOfType);
1295 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1296 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1297 return GetRoomsOfType(FilterTypes, bInverseSelection);
1298}

◆ GetShouldSpawnSpecialRoom()

bool AProceduralDungeonBuilder::GetShouldSpawnSpecialRoom ( ) const
private

Gets if the next spawn should take from the special list

1019{
1020 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetShouldSpawnSpecialRoom);
1021 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1022 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1023 //@ TEMP Fix, This can return null in SpawnNextSpecialRoom Mathmatically, and end the loop too early
1024 if(GetSpecialRoomClass() == nullptr){return false;}
1025 TArray<FDungeonSpawnRoom> SpecialRooms = GetRoomsOfType(EDungeonRoomType::SpecialRoom);
1026 LogDebugMessage(FString::Printf(TEXT("GetShouldSpawnSpecialRoom Rooms: %i"), SpecialRooms.Num()), true, true);
1027 if(SpecialRooms.IsEmpty()){return false;}
1028
1029 int32 TotalSpecialSpawnsRemaining = 0;
1030 int32 RequiredSpecialSpawnsRemaining = 0;
1031
1032 for(const auto& SpecialRoom : SpecialRooms)
1033 {
1034 if(SpecialRoom.bDisable)
1035 {
1036 continue;
1037 }
1038 // Calculate how many spawns remain for this room type.
1039 const int32 Remaining = FMath::Max(SpecialRoom.NumberToSpawn - SpecialRoom.NumberSpawned, 0);
1040 if(Remaining <= 0)
1041 {
1042 continue;
1043 }
1044 // If the room is required, count it toward required spawns.
1045 if (SpecialRoom.bRequired)
1046 {
1047 RequiredSpecialSpawnsRemaining += Remaining;
1048 }
1049 // If we have a spawn limit, only add the remaining count.
1050 // Otherwise, treat NumberToSpawn as a weight.
1051 if (SpecialRoom.bSpawnLimit)
1052 {
1053 TotalSpecialSpawnsRemaining += Remaining;
1054 }
1055 else
1056 {
1057 TotalSpecialSpawnsRemaining += SpecialRoom.NumberToSpawn;
1058 }
1059 }
1060 LogDebugMessage(FString::Printf(TEXT("GetShouldSpawnSpecialRoom SpecialRoomsToSpawn: %i"), TotalSpecialSpawnsRemaining), true, true);
1061
1062 if(TotalSpecialSpawnsRemaining <= 0){return false;}
1063 //- If we have more special than regular rooms, always use special //
1064 if(RequiredSpecialSpawnsRemaining >= NumberOfRoomsToSpawn){return true;}
1065
1066 // 2. Check we have enough exits ?
1068 {
1070 {
1071 return false;
1072 }
1073 if(AvailableExits.Num() < TotalSpecialSpawnsRemaining)
1074 {
1075 return false;
1076 }
1077 }
1078 // Calculate the probability of spawning a special room
1079 float Probability = static_cast<float>(TotalSpecialSpawnsRemaining) / static_cast<float>(NumberOfRoomsToSpawn);
1080 // Optionally, if there are required special rooms, boost the probability so they don't get left out.
1081 if (RequiredSpecialSpawnsRemaining > 0)
1082 {
1083 Probability = FMath::Max(Probability, 0.5f); // adjust the minimum probability as needed
1084 }
1085 // Generate a random float between 0 and 1 using the random stream
1086 const float RandomFloat = UKismetMathLibrary::RandomFloatInRangeFromStream(GetRandomStream(), 0.0f, 1.0f);
1087 // If the random number is less than the calculated probability, spawn a special room
1088 return RandomFloat < Probability;
1089}
void LogDebugMessage(const FString &Message, const bool bWarning=false, const bool bError=false) const
Definition ProceduralDungeonBuilder.cpp:1358
UClass * GetSpecialRoomClass() const
Definition ProceduralDungeonBuilder.cpp:1204

◆ GetShouldStopSpawningRooms()

bool AProceduralDungeonBuilder::GetShouldStopSpawningRooms ( ) const
private

Checks if Still rooms to spawn, if too many attempts

998{
1000 {
1001 return true;
1002 }
1004 {
1005 return true;
1006 }
1007 if(AvailableExits.Num() <= 0)
1008 {
1009 return true;
1010 }
1011 if(NumberOfRoomsToSpawn <= 0)
1012 {
1013 return true;
1014 }
1015 return false;
1016}
int32 TotalNumberOfRoomsToSpawn
Definition ProceduralDungeonBuilder.h:339
int32 RoomAttemptsMathMultiplier
Definition ProceduralDungeonBuilder.h:387

◆ GetSpecialRoomClass()

UClass * AProceduralDungeonBuilder::GetSpecialRoomClass ( ) const
private
1205{
1206 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::GetSpecialRoomClass);
1207 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
1208 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
1209 // 1. Get All Special room Types
1210 FDungeonSpawns SpecialRooms = FDungeonSpawns(GetRoomsOfType(EDungeonRoomType::SpecialRoom));
1211 TArray<FDungeonSpawnRoom>& SelectedRooms = SpecialRooms.GetRooms();
1212
1213 TArray<TSubclassOf<AActor>> SelectedRoomClasses;
1214 for(auto& SelectedRoom : SelectedRooms)
1215 {
1216 if(SelectedRoom.bDisable)
1217 {
1218 continue;
1219 }
1220 if(bCheckRoomTypes)
1221 {
1222 if(SelectedExit != nullptr && SelectedExit->GetAttachParentActor() != nullptr)
1223 {
1224 UClass* ConnectingRoomClass = SelectedExit->GetAttachParentActor()->GetClass();
1225 const EDungeonRoomType ConnectingRoomType = RoomTypes.FindType(ConnectingRoomClass);
1226 const bool bValidConnection = GetIsValidRoomConnection(ConnectingRoomType, SelectedRoom.CalculatedType);
1227 if(bValidConnection == false)
1228 {
1229 continue;
1230 }
1231 }
1232 }
1233 //- Check if the Room has a limit
1234 if(SelectedRoom.bSpawnLimit)
1235 {
1236 if(SelectedRoom.NumberSpawned >= SelectedRoom.NumberToSpawn)
1237 {
1238 continue;
1239 }
1240 }
1241 SelectedRoomClasses.Append(SelectedRoom.GetWeightedTypes());
1242 }
1243 if(SelectedRoomClasses.IsEmpty()){return nullptr;}
1244 return UProceduralBPLib::GetRandomClassFromStream(SelectedRoomClasses, GetRandomStream());
1245}

◆ GetStartingRoomClass()

UClass * AProceduralDungeonBuilder::GetStartingRoomClass ( )
private
1186{
1187 if(RoomTypes.IsEmpty())
1188 {
1189 LogDebugMessage("GetStartingRoomClass RoomTypes.IsEmpty", true);
1190 return nullptr;
1191 }
1193 {
1194 StartingRoomNumber = UKismetMathLibrary::RandomIntegerInRangeFromStream(GetRandomStream(), 0, (RoomTypes.Num() - 1));
1195 }
1197 {
1198 LogDebugMessage("GetStartingRoomClass RoomTypes.IsValidIndex", true);
1199 return nullptr;
1200 }
1202}
int32 StartingRoomNumber
Definition ProceduralDungeonBuilder.h:135
bool IsEmpty() const
Definition DungeonData.h:266
bool IsValidIndex(const int32 Index) const
Definition DungeonData.h:270
int32 Num() const
Definition DungeonData.h:274

◆ HideAllRoomRoofs()

void AProceduralDungeonBuilder::HideAllRoomRoofs ( )
protected
90{
91 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::HideAllRoomRoofs);
92 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
93 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
95 for(const auto DungeonRoom : AllDungeonRooms)
96 {
97 DungeonRoom->ToggleAllRoomRoofs(bHideRoomRoofs);
98 }
99}
bool bHideRoomRoofs
Definition ProceduralDungeonBuilder.h:393
void HideAllRoomRoofs()
Definition ProceduralDungeonBuilder.cpp:89

◆ IsOverlapping()

bool AProceduralDungeonBuilder::IsOverlapping ( const FBox & CandidateBox)
protected
218{
219 for(const FBox& ExistingBox : PlacedRoomBounds)
220 {
221 if(BoxesOverlap(CandidateBox, ExistingBox))
222 {
223 return true;
224 }
225 }
226 return false;
227}
static bool BoxesOverlap(const FBox &A, const FBox &B)
Definition ProceduralDungeonBuilder.cpp:210

◆ LogDebugError()

void AProceduralDungeonBuilder::LogDebugError ( const FString & Message) const
private

Gets random from the array

1354{
1355 LogDebugMessage(Message, true, true);
1356}

◆ LogDebugMessage()

void AProceduralDungeonBuilder::LogDebugMessage ( const FString & Message,
const bool bWarning = false,
const bool bError = false ) const
private
1360{
1361 if(bDebuggingMode == false && bError == false){return;}
1362 FOutputDevice* OutputDevice = GWarn;
1363 if(OutputDevice == nullptr){return;}
1364 FString NetModeString;
1365 switch(GetWorld()->GetNetMode())
1366 {
1367 case NM_Standalone:
1368 NetModeString = FString("SDL");
1369 break;
1370 case NM_DedicatedServer:
1371 NetModeString = FString("DServer");
1372 break;
1373 case NM_ListenServer:
1374 NetModeString = FString("LServer");
1375 break;
1376 case NM_Client:
1377 NetModeString = FString("Client");
1378 break;
1379 default:
1380 NetModeString = FString("Unknown");
1381 break;
1382 }
1383 const FString FullMessage = FString::Printf(TEXT("%s: AProceduralDungeonBuilder::%s"), *NetModeString, *Message);
1384 if(bError)
1385 {
1386 OutputDevice->Log(LogDungeonBuilder.GetCategoryName(), ELogVerbosity::Error, FullMessage);
1387 }
1388 else if(bWarning)
1389 {
1390 OutputDevice->Log(LogDungeonBuilder.GetCategoryName(), ELogVerbosity::Warning, FullMessage);
1391 }
1392 else
1393 {
1394 OutputDevice->Log(LogDungeonBuilder.GetCategoryName(), ELogVerbosity::Log, FullMessage);
1395 }
1396}
bool bDebuggingMode
Definition ProceduralDungeonBuilder.h:400

◆ LogDebugWarning()

void AProceduralDungeonBuilder::LogDebugWarning ( const FString & Message) const
private
1349{
1350 LogDebugMessage(Message, true);
1351}

◆ Multicast_DungeonComplete()

void AProceduralDungeonBuilder::Multicast_DungeonComplete ( int32 NumRooms)
protected

◆ OnAISpawned()

void AProceduralDungeonBuilder::OnAISpawned ( const int32 NumOfPawns)
protected

◆ OnConstruction()

void AProceduralDungeonBuilder::OnConstruction ( const FTransform & Transform)
overrideprotectedvirtual
50{
51 Super::OnConstruction(Transform);
52 if(Transform.IsValid() == false){return;}
53}

◆ OnDoorsSpawned()

void AProceduralDungeonBuilder::OnDoorsSpawned ( const int32 NumOfDoors)
protected

◆ OnDungeonComplete()

void AProceduralDungeonBuilder::OnDungeonComplete ( const int32 NumOfRooms)
protected

◆ OnRoomsComplete()

void AProceduralDungeonBuilder::OnRoomsComplete ( )
private

For use if there is a Delay,

909{
910 if(bLogDungeonSteps){LogDebugWarning("OnRoomsComplete");}
912 {
914 }
915 CloseHoles();
920}

◆ RemoveExitsByDistance()

void AProceduralDungeonBuilder::RemoveExitsByDistance ( TArray< USceneComponent * > & ExitsA,
TArray< USceneComponent * > & ExitsB ) const
private
654{
655 for (int32 i = 0; i < ExitsA.Num(); ++i)
656 {
657 if (!ExitsA[i]) { continue; }
658
659 const FVector LocationToCheck = ExitsA[i]->GetComponentLocation();
660
661 // Check against all other components after this one in the array
662 for (int32 j = i + 1; j < ExitsB.Num(); ++j)
663 {
664 if (!ExitsB[j]) { continue; }
665
666 // Ensure we are not comparing the same component instance
667 if (ExitsA[i] != ExitsB[j] &&
668 LocationToCheck.Equals(ExitsB[j]->GetComponentLocation(), ExitLocationDistanceOverlap))
669 {
670 // If the locations are the same, remove both exits from the array
671 ExitsB.RemoveAt(j); // Remove the second component first
672 ExitsA.RemoveAt(i); // Remove the first component
673
674 // After removing, decrement i to avoid skipping the next element
675 --i;
676 break; // Exit the inner loop and move to the next component
677 }
678 }
679 }
680}
float ExitLocationDistanceOverlap
Definition ProceduralDungeonBuilder.h:369

◆ ScheduleSpawn()

void AProceduralDungeonBuilder::ScheduleSpawn ( const FTimerDelegate::TMethodPtr< AProceduralDungeonBuilder > SpawnMethod)
protected
618{
620 {
621 GetWorld()->GetTimerManager().SetTimer(BuildDelayHandle, this, SpawnMethod, BuildDelayTime, false);
622 }
623 else
624 {
625 (this->*SpawnMethod)();
626 }
627}
float BuildDelayTime
Definition ProceduralDungeonBuilder.h:429
FTimerHandle BuildDelayHandle
Definition ProceduralDungeonBuilder.h:430

◆ SetDungeonValues()

bool AProceduralDungeonBuilder::SetDungeonValues ( )
private
374{
376 INC_DWORD_STAT(STAT_GenerateAttempts);
377
378 // 1. Check Valid
379 if(LastSpawnedRoom == nullptr){LogDebugWarning(FString::Printf(TEXT("SetDungeonValues LastSpawnedRoom")));return false;}
380 IDungeonRoom* NextDungeonRoom = Cast<IDungeonRoom>(LastSpawnedRoom);
381 if(NextDungeonRoom == nullptr)
382 {
383 LogDebugWarning(FString::Printf(TEXT("SetDungeonValues NextDungeonRoom")));
384 return false;
385 }
386 // 2. Add to list of all rooms, to set as ready at end //
387 AllDungeonRooms.AddUnique(NextDungeonRoom);
388
389 // 3. Apply Random
390 NextDungeonRoom->SetRandomStream(GetRandomStream());
391 // 3.1 Material
393 {
394 //@TODO Get Slot Name
395 //@TODO Instead should give an array of each Dynamic material, ones for glass, General etc.
396 // @ Get Matching Material?
398 }
399 //3.2 Roof Debug
400#if WITH_EDITOR
402 {
403 NextDungeonRoom->ToggleAllRoomRoofs(true);
404 }
405#endif // WITH_EDITOR
406
407 // 4. Add Exits to list
408 TArray<USceneComponent*> ExitsToAdd;
409 if(NextDungeonRoom->GetExitsRootComponent())
410 {
411 TArray<USceneComponent*> NewExits;
412 NextDungeonRoom->GetExitsRootComponent()->GetChildrenComponents(false, NewExits);
413 // 4.1 Check if any are overlapping the current exits
416 ExitsToAdd.Append(NewExits);
417 }
418 AvailableExits.Append(ExitsToAdd);
419
420 if(SelectedExit != nullptr)
421 {
422 // 5. Add Door Locations
423 if(NextDungeonRoom->GetShouldRoomSpawnDoorAtEntry(GetRandomStream()))
424 {
426
427 //@ TEST do we need to get it when we add to the list, and add into a scruct? or when we are adding the doors
428 // //@TEST Check if we can get the Parent of the Component
429 // // then we can get the Room that owns the Door, and Add that to the RoomActor
430 // if(SelectedExit->GetAttachParentActor() != nullptr)
431 // {
432 // UE_LOG(LogDungeonBuilder, Warning,TEXT("Parent Actor: %s"), SelectedExit->GetAttachParentActor()->GetHumanReadableName());
433 // }
434 }
435 // 6. Add Connecting Rooms
436 if(SelectedExit->GetAttachParentActor() != nullptr)
437 {
438 //- Add the Last room to the New room ->
439 NextDungeonRoom->AddAttachedRoom(SelectedExit->GetAttachParentActor());
440 //- Add the New room, to the Last room ->
441 IDungeonRoom* ExitDungeonRoom = Cast<IDungeonRoom>(SelectedExit->GetAttachParentActor());
442 if(ExitDungeonRoom != nullptr)
443 {
444 ExitDungeonRoom->AddAttachedRoom(LastSpawnedRoom);
445 }
446 }
447 // // 7. Remove Exit from List
448 // if(bDeleteExitBeforeSpawn == false)
449 // {
450 // AvailableExits.Remove(SelectedExit);
451 // }
452 }
453
454 // 8. Add AI Spawn Points
456 // 9. Add Values
458 RoomsSpawned++;
460 {
462 }
463 INC_DWORD_STAT(STAT_RoomsCreated);
464 return true;
465}
TArray< USceneComponent * > DoorLocations
Definition ProceduralDungeonBuilder.h:225
Definition DungeonRoom.h:21
virtual bool GetShouldRoomSpawnDoorAtEntry(const FRandomStream &Stream) const =0
virtual void ToggleAllRoomRoofs(const bool bForceHide)=0
virtual USceneComponent * GetExitsRootComponent() const =0
virtual void AddAttachedRoom(AActor *RoomActor)=0
virtual void SetDynamicMaterial(UMaterialInterface *Material)=0
virtual USceneComponent * GetAISpawnsRootComponent() const =0
virtual void SetRandomStream(const FRandomStream &Stream)=0

◆ SetInitialValues()

void AProceduralDungeonBuilder::SetInitialValues ( )
protected
131{
132 if(bLogDungeonSteps){LogDebugWarning("SetInitialValues");}
136}
TArray< int32 > DoorWeights
Definition ProceduralDungeonBuilder.h:199
TArray< TSubclassOf< AActor > > DoorTypes
Definition ProceduralDungeonBuilder.h:196
static void AddWeightsToArray(TArray< TSubclassOf< AActor > > &Array, const TArray< int32 > &Weights)
Definition ProceduralBPLib.cpp:96

◆ SetNumberOfRooms()

void AProceduralDungeonBuilder::SetNumberOfRooms ( )
private

Sets the Number Of Rooms

987{
988 if(bLogDungeonSteps){LogDebugWarning("Set Number Of Rooms");}
991 {
992 NumberOfRoomsToSpawn = UKismetMathLibrary::RandomIntegerInRangeFromStream(GetRandomStream(), MinNumberOfRoomsToSpawn, NumberOfRoomsToSpawn);
993 }
995}
bool bUseRandomNumberOfRooms
Definition ProceduralDungeonBuilder.h:141
int32 MinNumberOfRoomsToSpawn
Definition ProceduralDungeonBuilder.h:143

◆ SetRoomsReady()

void AProceduralDungeonBuilder::SetRoomsReady ( ) const
protected

Sets all rooms to be Ready

851{
852 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SetRoomsReady);
853 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
854 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
855 if(bLogDungeonSteps){LogDebugWarning("SetRoomsReady");}
856 if(bDebuggingMode){LogDebugMessage(FString::Printf(TEXT("SetRoomsReady DungeonRooms: %i"), AllDungeonRooms.Num()));}
857 for(const auto DungeonRoom: AllDungeonRooms)
858 {
859 if(DungeonRoom == nullptr){continue;}
860 DungeonRoom->SetReady();
861 }
862}

◆ SetSeed()

void AProceduralDungeonBuilder::SetSeed ( )
private

Sets the RandomStream

936{
937 if (!HasAuthority()) return;
938 if(bLogDungeonSteps){LogDebugWarning("Set Seed");}
940 {
941 LogDebugError("SetSeed bUseGameModeStream");
942 IProceduralGM* ProceduralGM = Cast<IProceduralGM>(UGameplayStatics::GetGameMode(this));
943 if(ProceduralGM == nullptr){LogDebugError("SetSeed ProceduralGM");}
944 if(ProceduralGM != nullptr)
945 {
946 RandomStreamPtr = &ProceduralGM->GetRandomStream();
947 if(RandomStreamPtr == nullptr){LogDebugError("SetSeed RandomStreamPtr");}
948 if(RandomStreamPtr != nullptr)
949 {
950 Seed = RandomStreamPtr->GetCurrentSeed();
951 bUsingGameModeSteam = true;
952 LogDebugMessage(FString::Printf(TEXT("GAME MODE SEED: %i"), Seed), true, true);
953 return;
954 }
955 }
956 }
958 {
959 UKismetMathLibrary::SeedRandomStream(RandomStream);
960 Seed = RandomStream.GetCurrentSeed();
961 }
962 else
963 {
964 UKismetMathLibrary::SetRandomStreamSeed(RandomStream, Seed);
965 }
966 if(RandomStreamPtr == nullptr)
967 {
969 }
970}
FRandomStream RandomStream
Definition ProceduralDungeonBuilder.h:359
int32 Seed
Definition ProceduralDungeonBuilder.h:180
bool bUseGameModeStream
Definition ProceduralDungeonBuilder.h:203
bool bUseRandomSeed
Definition ProceduralDungeonBuilder.h:178
bool bUsingGameModeSteam
Definition ProceduralDungeonBuilder.h:258
Definition ProceduralGM.h:20
virtual FRandomStream & GetRandomStream()=0

◆ SpawnAIAtLocation()

void AProceduralDungeonBuilder::SpawnAIAtLocation ( )
protected

Spawns Random AI at the Spawn points

815{
816 if (!HasAuthority()) return;
817 if(bLogDungeonSteps){LogDebugWarning("SpawnAIAtLocation");}
818 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SpawnAIAtLocation);
819 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
820 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
821 if(AIToSpawn <= 0){OnAISpawned(AISpawned);return;}
823 // @Todo Instead of Early Finish, there needs to be attempt limit, and try again.
824 if(AIClass == nullptr){OnAISpawned(AISpawned);return;}
826 if(SelectedAISpawn == nullptr){OnAISpawned(AISpawned);return;}
827 const FTransform SpawnTransform = SelectedAISpawn->GetComponentTransform();
828 const APawn* SpawnedAI = UAIBlueprintHelperLibrary::SpawnAIFromClass(GetWorld(), AIClass, nullptr, SpawnTransform.GetLocation());
829 if(SpawnedAI == nullptr)
830 {
831 LogDebugError(FString::Printf(TEXT("SpawnAIAtLocation SpawnedAI")));
835 return;
836 }
839
840 AIToSpawn--;
841 AISpawned++;
843 {
844 GetWorld()->GetTimerManager().SetTimer(BuildDelayHandle, this, &AProceduralDungeonBuilder::SpawnAIAtLocation, BuildDelayTime, false);
845 return;
846 }
848}
TArray< TSubclassOf< AActor > > AITypes
Definition ProceduralDungeonBuilder.h:212
TArray< USceneComponent * > AISpawnsFailed
Definition ProceduralDungeonBuilder.h:264
void OnAISpawned(const int32 NumOfPawns)
TArray< USceneComponent * > AISpawnsSelected
Definition ProceduralDungeonBuilder.h:262
bool bDelayEachAISpawn
Definition ProceduralDungeonBuilder.h:419

◆ SpawnAllRooms()

void AProceduralDungeonBuilder::SpawnAllRooms ( )
protected

Create first room at Actors location

139{
140 if(bLogDungeonSteps){LogDebugWarning("SpawnAllRooms");}
141 //@ TODO Get all Material Slot Names Possible?
142 // for Setting the right Material?
143 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SpawnAllRooms);
144 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
145 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
146 UWorld* World = GetWorld();
147 if(World == nullptr)
148 {
149 LogDebugWarning(FString::Printf(TEXT("SpawnAllRooms CalculateRoomExits: World is null")));
150 return;
151 }
152 for(FDungeonSpawnRoom& RoomSpawn : RoomTypes.GetRooms())
153 {
154 if (RoomSpawn.Type == nullptr){LogDebugWarning(FString::Printf(TEXT("SpawnAllRooms RoomSpawn.Type nullptr")));continue;}
155 AActor* TempRoom = World->SpawnActor<AActor>(RoomSpawn.Type, FTransform::Identity, SpawnParams);
156 if (TempRoom)
157 {
158 const IDungeonRoom* DungeonRoom = Cast<IDungeonRoom>(TempRoom);
159 if(DungeonRoom)
160 {
161 const int32 NumExits = DungeonRoom->GetNumOfExits();
162 RoomSpawn.CalculatedExits = NumExits;
163 const EDungeonRoomType RoomType = DungeonRoom->GetRoomType();
164 RoomSpawn.CalculatedType = RoomType;
165 const FBox RoomBounds = DungeonRoom->GetRoomBounds();
166 RoomSpawn.CalculatedRoomBounds = RoomBounds;
167 // RoomSpawn.bCalculatedMaterialSlot ? or on room
168 RoomSpawn.bCalculatedValues = true;
169 }
170 else
171 {
172 LogDebugWarning(FString::Printf(TEXT("SpawnAllRooms Room %s does not implement IDungeonRoom."), *RoomSpawn.Type->GetName()));
173 }
174 TempRoom->Destroy();
175 }
176 else
177 {
178 LogDebugWarning(FString::Printf(TEXT("SpawnAllRooms Failed to spawn temporary instance of %s."), *RoomSpawn.Type->GetName()));
179 }
180 }
181}
virtual int32 GetNumOfExits() const =0
virtual FBox GetRoomBounds() const =0
virtual EDungeonRoomType GetRoomType() const =0

◆ SpawnDoorAtLocation()

void AProceduralDungeonBuilder::SpawnDoorAtLocation ( )
protected

Closes empty exits after the generator is complete

771{
772 if (!HasAuthority()) return;
773 if(bLogDungeonSteps){LogDebugWarning("SpawnDoorAtLocation");}
774 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SpawnDoors);
775 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
776 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
777 if(DoorLocations.Num() <= 0){OnDoorsSpawned(DoorsSpawned);return;}
778 if(bSpawnDoors == false){OnDoorsSpawned(DoorsSpawned);return;}
781 if(DoorClass == nullptr){OnDoorsSpawned(DoorsSpawned);return;}
783 if(SelectedDoorSpawn == nullptr){OnDoorsSpawned(DoorsSpawned);return;}
784 const FTransform SpawnTransform = SelectedDoorSpawn->GetComponentTransform();
785 const AActor* NewDoor = GetWorld()->SpawnActor(DoorClass, &SpawnTransform, SpawnParams);
786 if(NewDoor == nullptr)
787 {
788 LogDebugError(FString::Printf(TEXT("SpawnDoors NewDoor Failed")));
792 return;
793 }
794 //@TEST Check if we can get the Parent of the Component
795 // then we can get the Room that owns the Door, and Add that to the RoomActor
796 if(SelectedExit->GetAttachParentActor() != nullptr)
797 {
798 //LogDebugMessage(FString::Printf(TEXT("Parent Actor: %s, Door: %s"), *SelectedExit->GetAttachParentActor()->GetName(), *NewDoor->GetName()));
799 }
800 else
801 {
802 LogDebugError(FString::Printf(TEXT("Parent Actor: Invalid, Door: %s"), *NewDoor->GetName()));
803 }
805 DoorsSpawned++;
807 {
808 GetWorld()->GetTimerManager().SetTimer(BuildDelayHandle, this, &AProceduralDungeonBuilder::SpawnDoorAtLocation, BuildDelayTime, false);
809 return;
810 }
812}
bool bDelayEachDoorSpawn
Definition ProceduralDungeonBuilder.h:421
int32 DoorLimit
Definition ProceduralDungeonBuilder.h:194
void OnDoorsSpawned(const int32 NumOfDoors)
TArray< USceneComponent * > DoorSpawnsFailed
Definition ProceduralDungeonBuilder.h:268
bool bSpawnDoors
Definition ProceduralDungeonBuilder.h:190
bool bLimitDoors
Definition ProceduralDungeonBuilder.h:192
USceneComponent * SelectedDoorSpawn
Definition ProceduralDungeonBuilder.h:254

◆ SpawnNextRoom()

void AProceduralDungeonBuilder::SpawnNextRoom ( )
protected

The function that loops creating rooms

296{
297 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SpawnNextRoom);
298 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
299 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
300 // 1. Choose an exit from an already placed room.
302 if(SelectedExit == nullptr)
303 {
304 LogDebugError("SpawnNextRoom No available exit found.");
305 return;
306 }
307
308 // 2. Pick a candidate room.
309 UClass* SelectedRoomClass = GetNewRoomClass();
310 if(SelectedRoomClass == nullptr)
311 {
312 LogDebugError("SpawnNextRoom SelectedRoomClass nullptr.");
313 return;
314 }
315 // 3.1 Look up the precomputed data for the candidate room.
316 FDungeonSpawnRoom* RoomData = RoomTypes.Find(SelectedRoomClass);
317 if(RoomData == nullptr)
318 {
319 LogDebugError(FString::Printf(TEXT("SpawnNextRoom: No precomputed data for %s"), *SelectedRoomClass->GetName()));
320 return;
321 }
322
323 // 4.1 Compute the candidate room’s world transform.
324 const FTransform SpawnTransform = SelectedExit->GetComponentTransform();
325
326 // 5.1 Compute the candidate room’s world bounds.
327 const FBox CandidateWorldBounds = RoomData->CalculatedRoomBounds.TransformBy(SpawnTransform);
328 // const FBox CandidateWorldBounds = RoomData->LocalBounds.TransformBy(SpawnTransform);
329
330 // 6. Check for overlap using our math (not physics overlaps).
331 if(IsOverlapping(CandidateWorldBounds))
332 {
333 LogDebugWarning("SpawnNextRoom Candidate room would overlap an existing room.");
335 {
336 DrawDebugBox(GetWorld(), CandidateWorldBounds.GetCenter(), CandidateWorldBounds.GetExtent(), FColor::Red, false, BuildDelayTime * 5.0f, 0, 1.0f);
337 }
338 // Option: Remove this exit so we do not try it again, then try spawning a room on another exit.
340 INC_DWORD_STAT(STAT_GenerateAttempts);
344 return;
345 }
346 // 7. Spawn the candidate room using the computed transform.
347 LastSpawnedRoom = GetWorld()->SpawnActor<AActor>(SelectedRoomClass, SpawnTransform, SpawnParams);
349 const bool bValidRoom = SetDungeonValues();
350 if(bValidRoom)
351 {
352 // 8. Save the candidate room’s bounds so future rooms can check it
353 PlacedRoomBounds.Add(CandidateWorldBounds);
354 AttemptChecker = 0;
355 RoomData->NumberSpawned++;
356 //@ TODO
357 // CheckForOverlappingExits();
358 }
359 else
360 {
361 // AvailableExits.Remove(SelectedExit);
362 if(LastSpawnedRoom != nullptr)
363 {
364 LastSpawnedRoom->Destroy();
365 }
366 INC_DWORD_STAT(STAT_RoomsDeleted);
368 }
369 // 11. Continue the spawning process (using your delay mechanism if needed).
371}
USceneComponent * GetNextExit()
Definition ProceduralDungeonBuilder.cpp:1091
bool bDrawFailedExits
Definition ProceduralDungeonBuilder.h:403

◆ SpawnSpecialRoom()

void AProceduralDungeonBuilder::SpawnSpecialRoom ( )
protected

The function that Spawns from the Special rooms List, only creating a certain amount of them

536{
537 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SpawnSpecialRoom);
538 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
539 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
540 // 1. Choose an exit from an already placed room.
541 // LogDebugWarning("SpawnSpecialRoom.");
543 if(SelectedExit == nullptr)
544 {
545 LogDebugError("SpawnSpecialRoom No available exit found.");
546 return;
547 }
548 // 2. Pick a candidate room.
549 UClass* SelectedRoomClass = GetSpecialRoomClass();
550 if(SelectedRoomClass == nullptr)
551 {
552 LogDebugError("SpawnSpecialRoom SelectedRoomClass nullptr.");
553 return;
554 }
555
556 // 3.1 Look up the precomputed data for the candidate room.
557 FDungeonSpawnRoom* RoomData = RoomTypes.Find(SelectedRoomClass);
558 if(RoomData == nullptr)
559 {
560 LogDebugError(FString::Printf(TEXT("SpawnSpecialRoom: No precomputed data for %s"), *SelectedRoomClass->GetName()));
561 return;
562 }
563 // LogDebugWarning("SpawnSpecialRoom. SpawnTransform");
564 // 4.1 Compute the candidate room’s world transform.
565 const FTransform SpawnTransform = SelectedExit->GetComponentTransform();
566
567 // 5.1 Compute the candidate room’s world bounds.
568 // const FBox CandidateWorldBounds = RoomData->LocalBounds.TransformBy(SpawnTransform);
569 const FBox CandidateWorldBounds = RoomData->CalculatedRoomBounds.TransformBy(SpawnTransform);
570
571 // 6. Check for overlap using our math (not physics overlaps).
572 if(IsOverlapping(CandidateWorldBounds))
573 {
574 LogDebugError(FString::Printf(TEXT("SpawnSpecialRoom: Candidate room would overlap an existing room %s"), *SelectedRoomClass->GetName()));
575 // Option: Remove this exit so we do not try it again, then try spawning a room on another exit.
577 INC_DWORD_STAT(STAT_GenerateAttempts);
579 {
581 }
582 else
583 {
585 }
586 return;
587 }
588 //LogDebugWarning("SpawnSpecialRoom. SpawnActor");
589
590 // 7. Spawn the candidate room using the computed transform.
591 LastSpawnedRoom = GetWorld()->SpawnActor<AActor>(SelectedRoomClass, SpawnTransform, SpawnParams);
593 const bool bValidRoom = SetDungeonValues();
594 if(bValidRoom)
595 {
596 AttemptChecker = 0;
597 LogDebugMessage(FString::Printf(TEXT("SpawnSpecialRoom: Room Spawned: %s"), *SelectedRoomClass->GetName()));
598 // 8. Save the candidate room’s bounds so future rooms can check against it.
599 PlacedRoomBounds.Add(CandidateWorldBounds);
600 RoomData->NumberSpawned++;
601 }
602 else
603 {
604 // AvailableExits.Remove(SelectedExit);
605 if(LastSpawnedRoom != nullptr)
606 {
607 LastSpawnedRoom->Destroy();
608 }
609 INC_DWORD_STAT(STAT_RoomsDeleted);
611 }
612 //LogDebugWarning("SpawnSpecialRoom. ContinueSpawnNextRoom");
613 // 11. Continue the spawning process (using your delay mechanism if needed).
615}

◆ SpawnStartingRoom()

void AProceduralDungeonBuilder::SpawnStartingRoom ( )
protected

Create first room at Actors location

253{
254 TRACE_CPUPROFILER_EVENT_SCOPE(AProceduralDungeonBuilder::SpawnStartingRoom);
255 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons);
256 SCOPE_CYCLE_COUNTER(STAT_ProceduralDungeons_Builder);
257 SET_DWORD_STAT(STAT_RoomsCreated, 0);
258 SET_DWORD_STAT(STAT_RoomsDeleted, 0)
259 SET_DWORD_STAT(STAT_GenerateAttempts, 0);
260 if(bLogDungeonSteps){LogDebugWarning("SpawnStartingRoom");}
261 if(RootComponent == nullptr){LogDebugError("SpawnStartingRoom RootComponent");return;}
262
263 UClass* StartingRoomClass = GetStartingRoomClass();
264 if(StartingRoomClass == nullptr){LogDebugError("SpawnStartingRoom StartingRoomClass");return;}
265
266 const FTransform StartTransform = RootComponent->GetComponentTransform();
267
268 LastSpawnedRoom = GetWorld()->SpawnActor(StartingRoomClass, &StartTransform, SpawnParams);
270 {
271 RootComponent->SetRelativeRotation(FRotator(0.0f, 180.0f,0.0f));
272 AvailableExits.Add(RootComponent);
273 }
274 const bool bValidRoom = SetDungeonValues();
275 if(bValidRoom)
276 {
277 // if(bUseSpawnNextRoomMathematically)
278 // {
279 const FDungeonSpawnRoom* RoomData = RoomTypes.Find(StartingRoomClass);
280 if(RoomData == nullptr)
281 {
282 LogDebugError(FString::Printf(TEXT("SpawnNextRoomMathematically: No precomputed data for %s"), *StartingRoomClass->GetName()));
283 return;
284 }
285 const FBox CandidateWorldBounds = RoomData->CalculatedRoomBounds.TransformBy(StartTransform);
286 PlacedRoomBounds.Add(CandidateWorldBounds);
287 // }
288 }
289 else
290 {
291 LogDebugError("SpawnStartingRoom Starting room Failed");
292 }
293}
bool bAddStartingExit
Definition ProceduralDungeonBuilder.h:398
UClass * GetStartingRoomClass()
Definition ProceduralDungeonBuilder.cpp:1185

Member Data Documentation

◆ AISpawned

int32 AProceduralDungeonBuilder::AISpawned = 0
private

Number of rooms spawned

◆ AISpawns

TArray<USceneComponent*> AProceduralDungeonBuilder::AISpawns
protected

◆ AISpawnsFailed

TArray<USceneComponent*> AProceduralDungeonBuilder::AISpawnsFailed
protected

◆ AISpawnsSelected

TArray<USceneComponent*> AProceduralDungeonBuilder::AISpawnsSelected
protected

◆ AIToSpawn

int32 AProceduralDungeonBuilder::AIToSpawn = 10
protected

◆ AITypes

TArray<TSubclassOf<AActor> > AProceduralDungeonBuilder::AITypes
protected

◆ AllDungeonRooms

TArray<IDungeonRoom*> AProceduralDungeonBuilder::AllDungeonRooms
private

◆ AttemptChecker

int32 AProceduralDungeonBuilder::AttemptChecker = 0
private

Total times we have tried to spawn a room

◆ AvailableExits

TArray<USceneComponent*> AProceduralDungeonBuilder::AvailableExits
protected

All available Exit Components

◆ bAddStartingExit

bool AProceduralDungeonBuilder::bAddStartingExit = false
private

◆ bApplyDynamicMaterial

bool AProceduralDungeonBuilder::bApplyDynamicMaterial = true
protected

◆ bCheckForJoiningRooms

bool AProceduralDungeonBuilder::bCheckForJoiningRooms = true
protected

◆ bCheckRoomExitCount

bool AProceduralDungeonBuilder::bCheckRoomExitCount = false
protected

◆ bCheckRoomTypes

bool AProceduralDungeonBuilder::bCheckRoomTypes = true
protected

◆ bComplete

bool AProceduralDungeonBuilder::bComplete = false
protected

If the builder is complete

◆ bCreatedInEditor

bool AProceduralDungeonBuilder::bCreatedInEditor = false
private

If the Dungeon was created in Editor

◆ bCreateOnBeginPlay

bool AProceduralDungeonBuilder::bCreateOnBeginPlay = true
protected

◆ bDebuggingMode

bool AProceduralDungeonBuilder::bDebuggingMode = true
private

◆ bDelayEachAISpawn

bool AProceduralDungeonBuilder::bDelayEachAISpawn = false
private

◆ bDelayEachDoorSpawn

bool AProceduralDungeonBuilder::bDelayEachDoorSpawn = false
private

◆ bDelayEachRoomBuild

bool AProceduralDungeonBuilder::bDelayEachRoomBuild = false
private

For showing the build process slowly, which can make it easier to find faults

◆ bDeleteExitBeforeSpawn

bool AProceduralDungeonBuilder::bDeleteExitBeforeSpawn = true
private

Should a possible exit be removed once selected, or after the actor has spawned false will guarantee that all rooms will try to spawn, causing more memory leaks true will remove exits that have failed to spawn a room, causing more fills, and likely fewer rooms than intended

◆ bDrawFailedExits

bool AProceduralDungeonBuilder::bDrawFailedExits = false
private

◆ bFillWithDeadEndRooms

bool AProceduralDungeonBuilder::bFillWithDeadEndRooms = false
protected

◆ bGetClosestExit

bool AProceduralDungeonBuilder::bGetClosestExit = false
protected

◆ bGiveRoomsRandomStream

bool AProceduralDungeonBuilder::bGiveRoomsRandomStream = false
private

◆ bHasInvalidClass

bool AProceduralDungeonBuilder::bHasInvalidClass = false
private

Saves if one of the Rooms is invalid

◆ bHideRoomRoofs

bool AProceduralDungeonBuilder::bHideRoomRoofs = false
private

◆ bLimitDoors

bool AProceduralDungeonBuilder::bLimitDoors = true
protected

◆ bLogDungeonSteps

bool AProceduralDungeonBuilder::bLogDungeonSteps = false
private

Log Each Main function of the builder

◆ bLogDungeonSummary

bool AProceduralDungeonBuilder::bLogDungeonSummary = true
private

Log main stats after build complete

◆ bRandomGetClosestExit

bool AProceduralDungeonBuilder::bRandomGetClosestExit = false
protected

◆ bResetRoomTypesOnComplete

bool AProceduralDungeonBuilder::bResetRoomTypesOnComplete = false
private

◆ bSpawnDoors

bool AProceduralDungeonBuilder::bSpawnDoors = true
protected

Actor with collision to Check if 2 rooms are joining

◆ BuildDelayHandle

FTimerHandle AProceduralDungeonBuilder::BuildDelayHandle
private

◆ BuildDelayTime

float AProceduralDungeonBuilder::BuildDelayTime = 0.1f
private

◆ bUseGameModeStream

bool AProceduralDungeonBuilder::bUseGameModeStream = true
protected

◆ bUseRandomNumberOfRooms

bool AProceduralDungeonBuilder::bUseRandomNumberOfRooms = false
protected

If true, Set the NumberOfRooms to the Max Amount

◆ bUseRandomSeed

bool AProceduralDungeonBuilder::bUseRandomSeed = true
protected

◆ bUsingGameModeSteam

bool AProceduralDungeonBuilder::bUsingGameModeSteam = false
protected

◆ CheckRoomExitCountMin

int32 AProceduralDungeonBuilder::CheckRoomExitCountMin = 3
protected

◆ DoorLimit

int32 AProceduralDungeonBuilder::DoorLimit = 10
protected

◆ DoorLocations

TArray<USceneComponent*> AProceduralDungeonBuilder::DoorLocations
protected

◆ DoorSpawnsFailed

TArray<USceneComponent*> AProceduralDungeonBuilder::DoorSpawnsFailed
protected

◆ DoorSpawnsSelected

TArray<USceneComponent*> AProceduralDungeonBuilder::DoorSpawnsSelected
protected

◆ DoorsSpawned

int32 AProceduralDungeonBuilder::DoorsSpawned = 0
private

◆ DoorTypes

TArray<TSubclassOf<AActor> > AProceduralDungeonBuilder::DoorTypes
protected

◆ DoorWeights

TArray<int32> AProceduralDungeonBuilder::DoorWeights
protected

How likely the Door is to be picked, 1 Standard, 2 double

◆ DungeonActors

TArray<AActor*> AProceduralDungeonBuilder::DungeonActors
protected

◆ ExitLocationDistanceOverlap

float AProceduralDungeonBuilder::ExitLocationDistanceOverlap = 0.1f
private

The max distance two exits have to be auto deleted

◆ ExitsToFill

TArray<USceneComponent*> AProceduralDungeonBuilder::ExitsToFill
protected

Exits that failed to spawn, but should be filed

◆ LastSpawnedRoom

AActor* AProceduralDungeonBuilder::LastSpawnedRoom = nullptr
protected

The Last Room that was Created

◆ MaterialDataTable

class UDataTable* AProceduralDungeonBuilder::MaterialDataTable = nullptr
protected

◆ MinNumberOfRoomsToSpawn

int32 AProceduralDungeonBuilder::MinNumberOfRoomsToSpawn = 2
protected

◆ NullRandomStream

FRandomStream AProceduralDungeonBuilder::NullRandomStream
private

◆ NumberOfRoomsToSpawn

int32 AProceduralDungeonBuilder::NumberOfRoomsToSpawn = 50
protected

◆ OverlappedComponents

TArray<UPrimitiveComponent*> AProceduralDungeonBuilder::OverlappedComponents
protected

◆ PlacedRoomBounds

TArray<FBox> AProceduralDungeonBuilder::PlacedRoomBounds
protected

◆ RandomClosesExitWeight

float AProceduralDungeonBuilder::RandomClosesExitWeight = 0.5f
protected

◆ RandomStream

FRandomStream AProceduralDungeonBuilder::RandomStream
private

Stored Stream to generate Random Numbers

◆ RandomStreamPtr

FRandomStream* AProceduralDungeonBuilder::RandomStreamPtr = nullptr
private

◆ RoomAttemptsBeforeFail

int32 AProceduralDungeonBuilder::RoomAttemptsBeforeFail = 5
private

How many times should we try to spawn a room before giving up, any higher than 5 is too risky

◆ RoomAttemptsMathMultiplier

int32 AProceduralDungeonBuilder::RoomAttemptsMathMultiplier = 5
private

Math Function is calculated differently, so it can have more Attempts

◆ RoomChecker

TSubclassOf<AActor> AProceduralDungeonBuilder::RoomChecker = nullptr
protected

◆ RoomMaterial

UMaterialInterface* AProceduralDungeonBuilder::RoomMaterial = nullptr
protected

◆ RoomMaterialInstance

UMaterialInstanceDynamic* AProceduralDungeonBuilder::RoomMaterialInstance = nullptr
protected

◆ RoomsSpawned

int32 AProceduralDungeonBuilder::RoomsSpawned = 0
private

Number of rooms spawned

◆ RoomTypes

FDungeonSpawns AProceduralDungeonBuilder::RoomTypes
protected

List of the Room types to Spawn in

◆ Seed

int32 AProceduralDungeonBuilder::Seed = 0
protected

◆ SelectedAISpawn

USceneComponent* AProceduralDungeonBuilder::SelectedAISpawn = nullptr
protected

◆ SelectedDoorSpawn

USceneComponent* AProceduralDungeonBuilder::SelectedDoorSpawn = nullptr
protected

◆ SelectedExit

USceneComponent* AProceduralDungeonBuilder::SelectedExit = nullptr
protected

◆ SpawnParams

FActorSpawnParameters AProceduralDungeonBuilder::SpawnParams
private

◆ SpecialRoomTypeClasses

TArray<TSubclassOf<AActor> > AProceduralDungeonBuilder::SpecialRoomTypeClasses
protected

◆ StartingAIToSpawn

int32 AProceduralDungeonBuilder::StartingAIToSpawn = 0
private

Saved Starting Special Rooms

◆ StartingNumberOfRoomsToSpawn

int32 AProceduralDungeonBuilder::StartingNumberOfRoomsToSpawn = 0
private

Saved number of rooms we are trying to spawn

◆ StartingRoomNumber

int32 AProceduralDungeonBuilder::StartingRoomNumber = 0
protected

From the RoomTypes Array, set to -1 for Random

◆ StartingRoomTypes

FDungeonSpawns AProceduralDungeonBuilder::StartingRoomTypes
private

Saved Starting room Classes

◆ TotalNumberOfRoomsToSpawn

int32 AProceduralDungeonBuilder::TotalNumberOfRoomsToSpawn = 0
private

Saved number of rooms * the Random Amount

◆ WallFill

TSubclassOf<AActor> AProceduralDungeonBuilder::WallFill = nullptr
protected

Wall to fill in any gaps


The documentation for this class was generated from the following files: