I’m trying to implement basic dungeon generator and can’t get proper transforms of child meshes.
Here is what I do:
- add
USceneComponent
asRootComponent
- create static mesh subobjects, attach to
RootComponent
- set created mesh transform to previous connected mesh with additional translation based on prev mesh extent.
I’m printing resulting transform and it looks ok, i.e. (100.0, 0.0, 0.0…) when previous object size is 100.0.
And here is the resulting image:
As you can see objects is spawned, but translation is too small (like 5.0 instead of 100.0).
I guess I’m doing something wrong in GenerateRoomSuitingNode
method, please see code below.
Related code:
ADungeonGenerator::ADungeonGenerator() {
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<USceneComponent>("SceneRoot");
MaxDepth = 10;
NodesCount = 0;
Generate();
SetActorEnableCollision(true);
}
void ADungeonGenerator::Generate() {
Nodes = TArray<FDungeonNode>();
FDungeonNode Root = FDungeonNode();
GenerateRoomSuitingNode(Root, Root, EDungeonNodeSide::None, false);
Nodes.Add(Root);
TraverseAndSpawnNodesFrom(Root);
}
void ADungeonGenerator::GenerateRoomSuitingNode(FDungeonNode& Parent, FDungeonNode& Node, EDungeonNodeSide Side, bool CalcTransform) {
static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeMeshAsset(TEXT("StaticMesh'/Game/Geometry/Meshes/Shape_Cube.Shape_Cube'"));
if (CubeMeshAsset.Succeeded()) {
NodesCount = NodesCount + 1;
FString Id = "NodeMesh";
Id.AppendInt(NodesCount);
UStaticMeshComponent* Mesh = CreateDefaultSubobject<UStaticMeshComponent>(*Id);
Mesh->SetStaticMesh(CubeMeshAsset.Object);
Mesh->SetupAttachment(RootComponent);
Node.Mesh = Mesh;
Mesh->SetMobility(EComponentMobility::Movable);
if (CalcTransform) {
Node.Transform = FTransform(Parent.TransformForNodeSide(Side));
UE_LOG(LogTemp, Warning, TEXT("Transf %s"), *Node.Transform.ToString());
}
Mesh->SetRelativeTransform(Node.Transform);
Mesh->UpdateComponentToWorld();
}
}
void ADungeonGenerator::TraverseAndSpawnNodesFrom(FDungeonNode& Node) {
TraverseAndSpawnNodeVia(Node, EDungeonNodeSide::North);
TraverseAndSpawnNodeVia(Node, EDungeonNodeSide::East);
TraverseAndSpawnNodeVia(Node, EDungeonNodeSide::South);
TraverseAndSpawnNodeVia(Node, EDungeonNodeSide::West);
}
void ADungeonGenerator::TraverseAndSpawnNodeVia(FDungeonNode& Node, EDungeonNodeSide Side) {
if (Node.GetTypeAt(Side) == EDungeonNodeSideType::Wall) return;
if (Node.Depth + 1 > MaxDepth) return;
FDungeonNode NewNode = FDungeonNode(Node, Side, EDungeonNodeSideType::Wall, EDungeonNodeSideType::Wall,
EDungeonNodeSideType::Wall, EDungeonNodeSideType::Wall);
GenerateRoomSuitingNode(Node, NewNode, Side);
Nodes.Add(NewNode);
TraverseAndSpawnNodesFrom(NewNode);
}
// FDungeonNode method
FTransform TransformForNodeSide(EDungeonNodeSide Side) const {
auto Extent = Mesh->CalcBounds(FTransform()).GetBox().GetExtent();
float Dx = 0.0;
float Dy = 0.0;
switch (Side) {
case EDungeonNodeSide::North:
Dy = Extent.Y*2;
break;
case EDungeonNodeSide::East:
Dx = Extent.X*2;
break;
case EDungeonNodeSide::South:
Dy = -Extent.Y*2;
break;
case EDungeonNodeSide::West:
Dx = -Extent.X*2;
break;
}
auto NewTransform = FTransform(Transform);
NewTransform.AddToTranslation(FVector(Dx, Dy, 0.0));
return NewTransform;
}