Hello everyone,
I am working on my game development project and built a basic modular dungeon generator. My problem now is that modules get spawned like a tree and at some point they will overlap each other which im trying to prevent by detecting a collision and trying a different module to connect at specific exitpoint.
All my modules are blueprint classes that inherit from my base C++ class AModule and then get assigned different meshes and exitpoints via blueprints. I cant seem to figure out how to detect collision in my C++ code. I would like to fire an event that gets then processed during runtime by my generator.
If you spawn it there’s a collision parameter (spawn always - ignore collision, reposition on collision, …) could this be a usable way?
Or you could use a position based grid system, so overlapping isn’t possible - at least if the module sizes dont exceed the grid “tile” size.
Currently my Algorithm looks like this
if (world){
//spawn starting module
AActor* startModule = GetWorld()->SpawnActor<AModule>(m_startModule, FVector(0.f, 0.f, 0.f), FRotator(0.f, 45.f, 0.f), spawnParams);
//get components from startmodule and paste in array
TArray<UChildActorComponent*> pendingExits;
startModule->GetComponents(pendingExits);
//the dungeon algorithm
for (int32 x = 0; x < m_iterrations; x++)
{
TArray<UChildActorComponent*> newExits;
for (int i = 0; i < pendingExits.Num(); i++)
{
//get random tag from i-th component
FName tag = pendingExits*->ComponentTags[FMath::RandRange(0, pendingExits*->ComponentTags.Num() - 1)];
//spawn new module at dummy location
FVector dummyLocation;
dummyLocation.Set(0, 0, -100);
//init to prevent error
AModule* newModule = GetWorld()->SpawnActor<AModule>(m_test, dummyLocation, FRotator::ZeroRotator, spawnParams);
newModule->Destroy();
//TODO
// *try to place without collision to other modules
// *if fail try again
// *if success proceed
// *if fails try with different module for *specified times*
// or end here and mark as not connected
//chose random module
//spawn module matching the random tag
if (tag == "corr")
{
int num = FMath::RandRange(0, m_corrs.Num() - 1);
newModule = GetWorld()->SpawnActor<AModule>(m_corrs[num], dummyLocation, FRotator::ZeroRotator, spawnParams);
}
else if (tag == "junc")
{
int num = FMath::RandRange(0, m_juncs.Num() - 1);
newModule = GetWorld()->SpawnActor<AModule>(m_juncs[num], dummyLocation, FRotator::ZeroRotator, spawnParams);
}
else if (tag == "room")
{
int num = FMath::RandRange(0, m_rooms.Num() - 1);
newModule = GetWorld()->SpawnActor<AModule>(m_rooms[num], dummyLocation, FRotator::ZeroRotator, spawnParams);
}
//get new module exits
TArray<UChildActorComponent*> newModuleExits;
newModule->GetComponents(newModuleExits);
//choose random exit
AActor* exitToMatch = newModuleExits[FMath::RandRange(0, newModuleExits.Num() - 1)]->GetChildActor();
//match exits
MatchExits(pendingExits*->GetChildActor(), exitToMatch);
//get remaining unconnected exits from new module
for (int e = 0; e < newModuleExits.Num(); e++)
{
if (newModuleExits[e]->GetChildActor() != exitToMatch)
newExits.Add(newModuleExits[e]);
}
//add placed verified module to array
m_dungeonModules.Add(newModule);
newModule = NULL;
}
//update pending exits
pendingExits = newExits;
}
//TODO
//* mark all unconnected exits and place *defined object*
}
I want to give my Artist as much freedom as possible thats why I dont want to implement a tile based system. My artists will be creating the rooms directly in the 3D modelling software. And the collision parameter would not work in this scenario as my modules get spawned to a dummylocation and afterwards rotated and translated to where they should be inside of the
void ADungeonController::MatchExits(AActor* exit1, AActor* exit2)
function
If you have a List of the modules you want to check collision against, you could simply call GetActorBounds and then construct an FBox object and do an AABB test using the FBox methods. If you don’t have a list, you could just use the UWorld object and call OverlapAnyTestByChannel(…).
Thank you. I will try that right away. And give feedback on whether it worked or not