I’m kind of stumped here… I’ve managed to create the array structure. but I can’t seem to figure out how to actually create my node actors…
WallNode Actor Class
.H
#pragma once
#include "GameFramework/Actor.h"
#include "WallNode.generated.h"
UCLASS()
class PROCCAVE_API AWallNode : public AActor
{
GENERATED_BODY()
// Variables
private:
// WallStatus - 0 = No Wall, 1 = Wall, 2-255 = Could Be Anything For Now!
uint8 WallStatus;
FVector Location;
public:
// Sets default values for this actor's properties
AWallNode();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Setters
FORCEINLINE void SetLocation(const FVector & NewLocation) { SetActorLocation(NewLocation); Location = NewLocation; }
FORCEINLINE void SetWallStatus(uint8 NewStatus) { WallStatus = NewStatus; }
// Getters
FORCEINLINE uint8 GetWallStatus() { return WallStatus; }
FORCEINLINE FVector GetLocation() { return Location; }
};
.CPP
#include "ProcCave.h"
#include "WallNode.h"
// Sets default values
AWallNode::AWallNode()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
// Default Location 0,0,0
SetActorLocation(FVector(0.0F, 0.0F, 0.0F));
Location = FVector(0.0F, 0.0F, 0.0F);
// Default Wall Status = 1, 1 = A Wall
WallStatus = 1;
}
// Called when the game starts or when spawned
void AWallNode::BeginPlay()
{
Super::BeginPlay();
}
And the generator class… There is some legacy code from the fixed size 2D array, that works fine, but I want to get this thing working so it can be dynamically sized.
.H
#pragma once
#include "GameFramework/Actor.h"
#include "WallNode.h"
#include "Generator.generated.h"
USTRUCT(BlueprintType)
struct FGridNodeRow
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grid Settings", meta = (ClampMin = "0", UIMin = "0"))
TArray<AWallNode*> Width;
void AddNewWidth() { Width.Add(NULL); }
FGridNodeRow() {}
};
USTRUCT(BlueprintType)
struct FGridNodeArray
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grid Settings", meta = (ClampMin = "0", UIMin = "0"))
TArray<FGridNodeRow> Height;
void AddNewHeight() { Height.Add(FGridNodeRow()); }
void AddUninitialized(const int32 GridHeight, const int32 GridWidth)
{
// Create Rows For Height
for (int32 h = 0; h < GridHeight; h++)
{
AddNewHeight();
}
// Create Width Nodes
for (int32 h = 0; h < GridHeight; h++)
{
for (int32 w = 0; w < GridWidth; w++)
{
Height[h].AddNewWidth();
}
}
}
void Clear()
{
if (Height.Num() <= 0) return;
// Destroy All Nodes
const int32 HeightTotal = Height.Num();
const int32 WidthTotal = Height[0].Width.Num();
for (int32 h = 0; h < HeightTotal; h++)
{
for (int32 w = 0; w < WidthTotal; w++)
{
if (Height[h].Width[w] && Height[h].Width[w]->IsValidLowLevel())
{
Height[h].Width[w]->Destroy();
}
}
}
// Empty
for (int32 h = 0; h < Height.Num(); h++)
{
Height[h].Width.Empty();
}
Height.Empty();
}
FGridNodeArray() {}
};
UCLASS()
class PROCCAVE_API AGenerator : public AActor
{
GENERATED_BODY()
// Variables
private:
FDateTime DateAndTime;
uint8 CaveMap[100][100] = { 0 };
uint32 safeSeed;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "0", ClampMax = "100", UIMin = "0", UIMax = "100"))
uint8 RandomFillPercentage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "0", UIMin = "0"))
int32 Seed;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings")
bool useRandomSeed;
UPROPERTY()
FGridNodeArray NodeGrid;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "0", UIMin = "0"))
int32 MapWidth;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map Settings", meta = (ClampMin = "0", UIMin = "0"))
int32 MapHeight;
// Functions
public:
// Sets default values for this actor's properties
AGenerator();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
private:
// Generate the Map
void GenerateMap();
void RandomFillMap();
void DrawDebug();
void RandomFillNodeMap();
};
.CPP
#include "ProcCave.h"
#include "Generator.h"
#include "DrawDebugHelpers.h"
// Sets default values
AGenerator::AGenerator()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
// Set Defaults
RandomFillPercentage = 50;
useRandomSeed = false;
Seed = 10;
safeSeed = uint32(Seed);
MapWidth = 100;
MapHeight = 100;
// Init Grid
NodeGrid.Clear();
NodeGrid.AddUninitialized(MapHeight, MapWidth);
}
// Called when the game starts or when spawned
void AGenerator::BeginPlay()
{
Super::BeginPlay();
GenerateMap();
//DrawDebug();
}
void AGenerator::GenerateMap()
{
//RandomFillMap();
RandomFillNodeMap();
}
void AGenerator::RandomFillMap()
{
if (useRandomSeed) {
uint64 rawtime = DateAndTime.ToUnixTimestamp();
safeSeed = uint32(rawtime);
}
FRandomStream psuRandom = FRandomStream(Seed);
for (uint8 x = 0; x < 100; x++) {
for (uint8 y = 0; y < 100; y++) {
CaveMap[x][y] = (FMath::RandRange(0, 100) < RandomFillPercentage) ? 1 : 0;
// iterate the seed
uint32 cSeed = psuRandom.GetCurrentSeed();
uint32 nSeed = (cSeed * 3) + 1;
psuRandom.Initialize(nSeed);
}
}
}
void AGenerator::RandomFillNodeMap()
{
if (useRandomSeed) {
uint64 rawtime = DateAndTime.ToUnixTimestamp();
safeSeed = uint32(rawtime);
}
FRandomStream psuRandom = FRandomStream(Seed);
for (uint8 x = 0; x < MapWidth; x++) {
for (uint8 y = 0; y < MapHeight; y++) {
NodeGrid.Height[x].Width[y] = GetWorld()->SpawnActor(AWallNode->AWallNode());
NodeGrid.Height[x].Width[y]->SetActorLocation(FVector(x*100, y*100, 0));
NodeGrid.Height[x].Width[y]->SetWallStatus(((FMath::RandRange(0, 100) < RandomFillPercentage) ? 1 : 0));
// iterate the seed
uint32 cSeed = psuRandom.GetCurrentSeed();
uint32 nSeed = (cSeed * 3) + 1;
psuRandom.Initialize(nSeed);
}
}
}
void AGenerator::DrawDebug()
{
if (CaveMap != NULL) {
for (uint8 x = 0; x < 100; x++) {
for (uint8 y = 0; y < 100; y++) {
FVector position = FVector(x * 100.0F, y * 100.0F, 0.0F);
if (CaveMap[x][y] == 1) { DrawDebugPoint(GetWorld(), position, 5.0F, FColor(255, 0, 0), false, 60.0F, 0); }
else { DrawDebugPoint(GetWorld(), position, 5.0F, FColor(0, 0, 255), false, 60.0F, 0); }
}
}
}
}
The main issue, as far as I can tell, seems to be in this function:
void AGenerator::RandomFillNodeMap()
{
if (useRandomSeed) {
uint64 rawtime = DateAndTime.ToUnixTimestamp();
safeSeed = uint32(rawtime);
}
FRandomStream psuRandom = FRandomStream(Seed);
for (uint8 x = 0; x < MapWidth; x++) {
for (uint8 y = 0; y < MapHeight; y++) {
NodeGrid.Height[x].Width[y] = GetWorld()->SpawnActor(AWallNode->AWallNode());
NodeGrid.Height[x].Width[y]->SetActorLocation(FVector(x*100, y*100, 0));
NodeGrid.Height[x].Width[y]->SetWallStatus(((FMath::RandRange(0, 100) < RandomFillPercentage) ? 1 : 0));
// iterate the seed
uint32 cSeed = psuRandom.GetCurrentSeed();
uint32 nSeed = (cSeed * 3) + 1;
psuRandom.Initialize(nSeed);
}
}
}