I have a dungeon generator C++ class, with a function that gets a random location within the generated dungeon. It does so by getting the center coordinates of a random cell in the dungeon, and offsetting it by the width/height of the cell by a random amount.
Here is a simplified version of the function:
FVector2D AAHRDungeonGenerator::GetRandomLocationInDungeon()
{
FVector2D cellLocation = GetRandomCellLocation();
cellLocation.X += randomStream.FRandRange(-500, 500);
cellLocation.Y += randomStream.FRandRange(-500, 500);
return cellLocation;
}
Using Blueprints, I’ve made it so this function runs 10000 times and draws a point at the location returned. This is how that looks ingame:
The pattern that gets produced is strange. The Y offset is behaving as expected, generating dots along the entire height of the cell, but the X offset only deviates a tiny amount.
Noticing that the Y was working perfectly as expected, I tried adding a throwaway FRandomStream call to the function, as shown here:
FVector2D AAHRDungeonGenerator::GetRandomLocationInDungeon()
{
FVector2D cellLocation = GetRandomCellLocation();
float throwawayVariable = randomStream.FRandRange(0, 1);
cellLocation.X += randomStream.FRandRange(-500, 500);
cellLocation.Y += randomStream.FRandRange(-500, 500);
return cellLocation;
}
And, bizarrely, this causes the function to behave perfectly as expected:
So… I’m not really sure what to make of this. It’s like my randomStream property needs to be “primed” with a completely unused call before actually using it for some game logic.
The throwaway variable workaround seems to be working fine for addressing the problem, but obviously it’s really smelly. I’d love to know why FRandomStream doesn’t work the way I thought it would in the first example shown above.
Here are some additional details about the randomStream property in my dungeon generator class, incase they’re relevant:
randomStream Property
The randomStream property is a UPROPERTY that is created in the header file, as shown here (all other properties/functions removed for clarity):
UCLASS()
class HARVESTREMAKE_API AAHRDungeonGenerator : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
FRandomStream randomStream = FRandomStream();
}
randomStream runs Initialize() in my GenerateDungeon function, which runs well before the GetRandomLocationInDungeon() function:
void AAHRDungeonGenerator::GenerateDungeon(int seed)
{
randomStream.Initialize(seed);
ClearDungeon();
GenerateRooms();
GenerateHallways();
SpawnCells();
SpawnEnemies(); // This is the function that uses GetRandomLocationInDungeon()
}