Navigating a procedually generated galaxy.

​Hello,

I’ve been messing around with procedural galaxy generation. I have a script that spits out a bunch of points given the Vector the position needs to be in increments of 1 so

X:0, Y:0, Z:0 would generate 68 stars each with there own coordinates relative to that “cell”
X:1, Y:0, Z:0 would generate 66 stars each with there own coordinates relative to that “cell”
X:2, Y:0, Z:0 would generate 63 stars each with there own coordinates relative to that “cell”

To show these stars I expand the point by multiplying by 10 so the cell is 10x10x10

X:0, Y:0, Z:0
X:10, Y:0, Z:0
X:20, Y:0, Z:0

This works great and I can generate a “galaxy” as seen below. These are instance static meshes, probably not the best way to do this but it works, for now.

What’s the issue?
The script I have will generate 400+ billion stars, obviously way too many to put on the screen at any one time. The above image is 0.005% of all stars that the script can generate.

I don’t want to generate all the stars like this, I want to generate stars around the player and as the player moves through the map it will generate more stars in that direction.
I have, what I think, is a really convoluted, messy way of doing this, see below



TArray<FStar> AGalaxy::GenerateGrid(FVector playerPosition, bool coordinateChangedOverride)
{
    TArray<FStar> foundStars;
    bool bCoordinateChange;
    FVector newLocation = CheckPositionAndSet(playerPosition, bCoordinateChange, coordinateChangedOverride);


    if (bCoordinateChange) {

        int initX = newLocation.X - 20;
        int endX = newLocation.X + 20;
        int initY = newLocation.Y - 20;
        int endY = newLocation.Y + 20;
        int initZ = newLocation.Z - 20;
        int endZ = newLocation.Z + 20;

        for (auto XPos = initX; XPos <= endX; XPos += 10) {
            for (auto YPos = initY; YPos <= endY; YPos += 10) {
                for (auto ZPos = initZ; ZPos <= endZ; ZPos += 10) {

                    FVector GeneratedGrid = FVector(XPos, YPos, ZPos);
                    if (!GI->GeneratedGrids.Contains(GeneratedGrid)) {
                        foundStars.Append(StarGenerator->GenerateStars(XPos, YPos, ZPos));

                    }

                }
            }
        }

    }

    return found stars;
}

FVector AGalaxy::CheckPositionAndSet(FVector playerPosition, bool &bCoordinateChange, bool coordinateChangedOverride)
{
    playerCurrentPosition = playerPosition;
    playerPosition = playerPosition.operator/(20000); //Ive expanded to galaxy further the 10 on this code example
    int const CurrentPositionX = round(playerPosition.X);
    int const CurrentPositionY = round(playerPosition.Y);
    int const CurrentPositionZ = round(playerPosition.Z);
    FVector newLocation;

    bCoordinateChange = false;
    const float XRemainder = CurrentPositionX % 10;
    if ((abs(CurrentPositionX) % 10 > 0 || CurrentPositionX % 10 == 0) && CurrentPositionX != originalPositionX) {
        if (CurrentPositionX < 0) {
            newLocation.X = CurrentPositionX - (XRemainder + 10);
        }
        else {
            newLocation.X = CurrentPositionX - XRemainder;
        }

        if (newLocation.X != originalPositionX) {
            bCoordinateChange = true;
            originalPositionX = newLocation.X;
        }
    } else {
        newLocation.X = originalPositionX;
    }


    const float YRemainder = CurrentPositionY % 10;
    if ((abs(CurrentPositionY) % 10 > 0 || CurrentPositionY % 10 == 0) && CurrentPositionY != originalPositionY) {
        if (CurrentPositionY < 0) {
            newLocation.Y = CurrentPositionY - (YRemainder + 10);
        }
        else {
            newLocation.Y = CurrentPositionY - YRemainder;
        }

        if (newLocation.Y != originalPositionY) {
            bCoordinateChange = true;
            originalPositionY = newLocation.Y;
        }
    } else {
        newLocation.Y = originalPositionY;
    }

    const float ZRemainder = CurrentPositionZ % 10;
    if ((abs(CurrentPositionZ) % 10 > 0 || CurrentPositionZ % 10 == 0) && CurrentPositionZ != originalPositionZ) {
        if (CurrentPositionZ < 0) {
            newLocation.Z = CurrentPositionZ - (ZRemainder + 10);
        }
        else {
            newLocation.Z = CurrentPositionZ - ZRemainder;
        }

        if (newLocation.Z != originalPositionZ) {
            bCoordinateChange = true;
            originalPositionZ = newLocation.Z;
        }

    } else {
        newLocation.Z = originalPositionZ;
    }

    if(coordinateChangedOverride)
    {
        bCoordinateChange = true;
    }

    return newLocation;
}


GenerateGridAroundPlayer is called on every tick, if the previous position has changed then we add more stars, this does work and generates the grids around the user, but it feels dirty.

Finally after all that my question:

Is there a cleaner, simpler way of doing this… have I just reinvented the wheel?

Thanks for any help.