Skip to content

Instantly share code, notes, and snippets.

@cfr
Created October 17, 2016 09:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cfr/2f35e16933147e101034da6355721512 to your computer and use it in GitHub Desktop.
Save cfr/2f35e16933147e101034da6355721512 to your computer and use it in GitHub Desktop.
// cfr.pw
#include "JG.h"
#include "DungeonGenerator.h"
ADungeonGenerator::ADungeonGenerator() {
// 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;
RootComponent = CreateDefaultSubobject<USceneComponent>("SceneRoot");
MaxDepth = 3;
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);
//for (auto& Node : Nodes) {
// GenerateRoomSuitingNode(Node);
//}
}
// loads new node mesh and attaches to parent with bounds-based transform
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) {
Mesh->SetRelativeLocation(Parent.TranslationForNodeSide(Side));
UE_LOG(LogTemp, Warning, TEXT("Relative location: %s"), *Mesh->RelativeLocation.ToString());
Node.Transform = FTransform(Mesh->RelativeRotation, Mesh->RelativeLocation, Mesh->RelativeScale3D);
UE_LOG(LogTemp, Warning, TEXT("Transform: %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);
}
// Called when the game starts or when spawned
void ADungeonGenerator::BeginPlay() {
Super::BeginPlay();
}
// Called every frame
void ADungeonGenerator::Tick(float DeltaTime) {
Super::Tick(DeltaTime);
}
// cfr.pw
#pragma once
#include "GameFramework/Actor.h"
#include "DungeonGenerator.generated.h"
UENUM(BlueprintType, meta = (Bitflags))
enum class EDungeonNodeSide: uint8
{
None,
North,
East,
South,
West
};
ENUM_CLASS_FLAGS(EDungeonNodeSide);
UENUM(BlueprintType)
enum class EDungeonNodeSideType: uint8
{
Unknown,
Root,
Door,
Wall,
Hall
};
USTRUCT()
struct FDungeonNode
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Enum)
EDungeonNodeSideType NorthSideType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Enum)
EDungeonNodeSideType EastSideType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Enum)
EDungeonNodeSideType SouthSideType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Enum)
EDungeonNodeSideType WestSideType;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UStaticMeshComponent* Mesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
int32 Depth;
UPROPERTY()
float SizeX;
UPROPERTY()
float SizeY;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
FTransform Transform;
EDungeonNodeSideType GetTypeAt(EDungeonNodeSide Side) const {
switch (Side) {
case EDungeonNodeSide::North:
return NorthSideType;
case EDungeonNodeSide::East:
return EastSideType;
case EDungeonNodeSide::South:
return SouthSideType;
case EDungeonNodeSide::West:
return WestSideType;
}
return EDungeonNodeSideType::Unknown;
}
FDungeonNode() {
Depth = 0;
NorthSideType = EDungeonNodeSideType::Door;
EastSideType = EDungeonNodeSideType::Door;
SouthSideType = EDungeonNodeSideType::Door;
WestSideType = EDungeonNodeSideType::Door;
Transform = FTransform();
}
FDungeonNode(FDungeonNode previous, EDungeonNodeSide side,
EDungeonNodeSideType n, EDungeonNodeSideType e, EDungeonNodeSideType s, EDungeonNodeSideType w) {
Depth = previous.Depth + 1;
NorthSideType = n;
EastSideType = e;
SouthSideType = s;
WestSideType = w;
}
FVector TranslationForNodeSide(EDungeonNodeSide Side) const {
auto Extent = Mesh->CalcBounds(Mesh->ComponentToWorld).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;
}
return FVector(Dx, Dy, 0.0f);
}
};
UCLASS()
class JG_API ADungeonGenerator : public AActor
{
GENERATED_BODY()
void GenerateRoomSuitingNode(FDungeonNode& Parent, FDungeonNode& Node, EDungeonNodeSide Side, bool CalcTransform = true);
void TraverseAndSpawnNodesFrom(FDungeonNode& Node);
void TraverseAndSpawnNodeVia(FDungeonNode& Node, EDungeonNodeSide Side);
void Generate();
public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Generated Meshes")
int32 MaxDepth;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Generated Meshes")
int32 NodesCount;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Generated Meshes")
TArray<FDungeonNode> Nodes;
// Sets default values for this actor's properties
ADungeonGenerator();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment