Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Random dungeon generation, how can i tell the script which rooms to lay down next? [Code Included]

Asked by 7 years ago
Edited 7 years ago

got a complicated one for you today guys. im totally stumped. Im making a random dungeon generator script, and i cant figure out how to tell LUA what room to lay down next. The rooms i made for the dungeon each have a different amount of exit parts, and there are different sized rooms as well. so a big or small room can have anywhere from 1-4 exits each. The problem im having is connecting these rooms. Heres what i got:

--ace12345678135
-- I have no idea what im doing, but this is about to get very, very complicated.
local rooms = workspace["Room Templates"]:GetChildren() -- the room models
local world = workspace.World-- this is a folder
local placed = 0 -- keep track of how many rooms are placed
local tracker1 = 1 -- to give each location part in a model a name
math.randomseed(tick())
local RR = math.random(10,16)
------------------------------------------------------------------------------
for i = 1,RR,1 do
    -- section 1 label all parts locations to ready the next rooms to be added
    if placed == 1 then
        local createrooms = world.Room1:GetChildren()
            for _, v in pairs(createrooms) do
                if v.Name == "Part" then    
                local newvar = Instance.new("Vector3Value", v)
                newvar.Name = tracker1
                newvar.Value = v.CFrame.p
                tracker1 = tracker1 + 1
            end
        end 
        -- section 2, heres where it gets complicated.
            local mapname = workspace.World:GetChildren()
            for _, v in pairs(mapname) do
                if v.Name == "1:1 End" then
--i gave up here. i realized that i would have to list all
--compatible possibilities and put those into if statements
--so i would be here for hours just listing possible rooms
--maybe you know something i dont and can fix this but im stumped.
                end
            end


        placed = placed + 1 
    end
------------------------------------------------------------------------------
    -- if you havent placed a room, place a room.
    if placed == 0 then
    local cell = rooms[math.random(#rooms)]:clone()
    cell.Parent = world
    cell.PrimaryPart = cell.Floor
    local movpos = Vector3.new(0,70,0)
    cell:MoveTo(movpos)
    placed = placed + 1
    end



end

there are no errors in this script, i just dont know how to tell the script what to do next without creating a plethera of "if" statements. any help is appreciated

0
When you said listing all the combinations, did you mean there could be 1:2 End and 2:2 End as a room? Volodymyr2004 293 — 7y
0
no, i mean all options that would lead to more rooms, unless the room has more than one exit, then it would randomly decide whether that room gets a room with more exits or just a dead end. these are just the first 2 steps out of 16 i would have to write if i did it this way. i would not only have to list all possible exits for that room, but the next room, and the next room, all the way up to the ace12345678135 50 — 7y
0
16th possible room ace12345678135 50 — 7y

1 answer

Log in to vote
2
Answered by
tkcmdr 341 Moderation Voter
7 years ago

Hey ace12345678135!

I can certainly relate with your troubles, because I have, in the past, made something similar myself! Making a procedural dungeon generator can be a whole lot of fun, but it's not without its challenges...

To start, let's move that room model into ServerStorage so that it's out of the way. That done, let's get started with the basics:

local RoomTemplates = game.ServerStorage:WaitForChild("Room Templates"):GetChildren();

-- A folder that will contain all rooms spawned. Easy to empty.
local RoomFolder        = Instance.new("Folder", game.Workspace);
local StartRoom     = game.ServerStorage["Room Templates"]:FindFirstChild("Room1");

local function AppendRoom(existingRoom, newRoom)
    local newRoom = newRoom:Clone();

    newRoom:SetPrimaryPartCFrame(existingRoom.ExitPart.CFrame);

    newRoom.Parent = RoomFolder;

    return newRoom;
end;

-- Clear RoomFolder, create a new start room, and from the provided start room, append new rooms until we reach roomCount.
local function GenerateDungeon(roomCount)
    RoomFolder:ClearAllChildren();

    local lastRoom      = StartRoom:Clone();
    lastRoom.Parent = RoomFolder;

    for i = 1, roomCount do
        local chosenRoom    = RoomTemplates[math.random(#RoomTemplates)];
        local conditions    = (
            lastRoom and
            lastRoom:FindFirstChild("ExitPart") and
            chosenRoom.Name ~= "Room1" and
            chosenRoom.PrimaryPart and
            chosenRoom:FindFirstChild("ExitPart")
            -- Add conditions as needed.
        );

        if (conditions) then
            lastRoom = AppendRoom(lastRoom, chosenRoom);
        end;
    end;
end;

if (StartRoom) then
    GenerateDungeon(math.random(10, 20));
end;

You will notice that instead of using MoveTo, I used a function called SetPrimaryPartCFrame. This was intentional. SetPrimaryPartCFrame works essentially the same way, but uses CFrame to position, which means that your models will be positioned where they belong without exception.

Another thing you may have noticed is that I use two different parts to position rooms. One named PrimaryPart, and another, ExitPart. PrimaryPart is actually a property of Model that you can set to any part within the model. This is important. When you use SetPrimaryPartCFrame, it sets the position of that part, and moves the rest of the model to the same position relative to it. So, by setting a model's PrimaryPart CFrame to the CFrame of ExitPart, I effectively put the rooms together.

However, the positioning of PrimaryPart and ExitPart is crucial. PrimaryPart will be put in the same position as ExitPart, and the rest of the model will be placed around it. ExitPart of a room is where the door/hole/whatever of a certain room leads to another room. If PrimaryPart of the new room is where the entrance is, then the rooms will (if you positioned ExitPart and PrimaryPart correctly) fit together perfectly every time. To make positioning simple, make both the ExitParts and PrimaryParts of each room the same size, and place them in a consistent manner for each room in your game.

Having done that, simply set the PrimaryPart property of each room's Model, put them back into Room Templates and run the game. If you forgot to set the PrimaryPart of a model, the script will give you an error letting you know. Additionally, your rooms' positioning might be a bit loopy at first (trust me, it takes a bit to get the positions right sometimes, if you're not careful!) due to incorrect rotation or slight imperfections of the positioning or one or both parts, but when done correctly, the rooms will always have a standardized way of fitting into each other. For each new room you make, simply give it a PrimaryPart to act as the placeholder for the entryway, and have an ExitPart for the place where the exit is.

The PrimaryPart name convention I used is because that is the name for, well, a Model's PrimaryPart property. The name ExitPart, however, was made up. You could name it something else, but ExitPart seems pretty reasonable. Also note that PrimaryPart and ExitPart are placeholder parts. They do not need to be visible or collidable, since they only serve to help the rooms fit together consistently.

Now, I never did make a way for rooms to branch...

... that was intentional. There are multiple ways to do that, and I'm not sure what would best fit you. There is a point at which you'll be faced with problems like preventing rooms from running into each other and making the dungeon structure (semi-)reasonable. For now, tweak the existing game until you're satisfied that it will work consistently. Block the additional exits until you know how you want to work on additional paths. If you get stuck, though, feel free to message me.

It's worth noting that the above code was written completely from scratch and was not tested at all. It may or may not have problems, but I'm confident you'll be able to correct them if they turn up. Let me know if I made any mistakes, nonetheless. ;)

Have a good one, ace12345678135. Best of luck with your game, too!

Warm regards, tkcmdr

0
sorry it took so long, i accepted your answer but i already found the solution now, if i had seen this earlier that might have changed but i will still keep this as notes in case i need to do a rework for any reason. and the reason i used MoveTo instead of set primary part CFrame is i needed an easier way to detect overlaps in the dungeon. I cant go too much into detail since i have a team that is ace12345678135 50 — 7y
Ad

Answer this question