Help optimizing a generation module

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

im trying to make a backrooms-ish style game to mess around with my friends in
that has smooth random section generation around the players
(infinite)

  1. What is the issue? Include screenshots / videos if possible!

ive got it somewhat working but its SO LAGGY
and when i turn the loop speed down to just a task.wait() it crashes the studio

How would i fix this?

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

slowing down the loop does work when your first starting out, but it wont really matter when you play for longer as it has to loop through LOTS of generated Sections

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

modules code

local module = {}


local function RandomSection()
	local Sections = script.Sections:GetChildren()
	return Sections[math.random(1, #Sections)]
end

local function HasTag(Obj,TagName)
	for i,v in pairs(Obj:GetTags()) do
		if v == TagName then
			return true
		end
	end
	return false
end

local function InverseVector(Vec)
	local New
	local x,y,z
	if Vec.X ~= 0 then
		x = -Vec.X
	else
		x = 0
	end
	if Vec.Y ~= 0 then
		y = -Vec.Y
	else
		y = 0
	end
	if Vec.Z ~= 0 then
		z = -Vec.Z
	else
		z = 0
	end
	return Vector3.new(x,y,z)
end



module.Generate = function(From)
	local CollectionService = game:GetService("CollectionService")
	local function Create(offset)
		if not HasTag(From,("Generated"..tostring(offset))) then
			CollectionService:AddTag(From,"Generated"..tostring(offset))
			local Section = RandomSection():Clone()
			Section:PivotTo(From.PrimaryPart.CFrame+offset)
			Section:PivotTo(CFrame.new(Section.PrimaryPart.Position)*CFrame.fromEulerAnglesXYZ(0,0,0))
			Section.Parent = workspace.GeneratedRooms
			CollectionService:AddTag(Section,"Generated"..tostring(InverseVector(offset)))
		end
	end
	CollectionService:AddTag(From,"Generated")


	
	Create(Vector3.new(0,0,From.PrimaryPart.Size.Z))
	Create(Vector3.new(0,0,-From.PrimaryPart.Size.Z))
	Create(Vector3.new(From.PrimaryPart.Size.X,0,0))
	Create(Vector3.new(-From.PrimaryPart.Size.X,0,0))

end


module.TrackRange = function(Part)
	local Range = 100

	while task.wait() do
		if Part then
			
			for i,v in pairs(workspace.GeneratedRooms:GetChildren()) do
				if (Part.Position-v.PrimaryPart.Position).Magnitude < Range and not HasTag(v,"Generated") then
					module.Generate(v)
				end
			end
		else
			break
		end
	end
	
end


return module

the place file:
GENERATION.rbxl (58.0 KB)

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

local function HasTag(Obj,TagName)
	for i,v in pairs(Obj:GetTags()) do
		if v == TagName then
			return true
		end
	end
	return false
end

this can simply be table.find.


I don’t see any use for the if statements in here. This is simply

local function InverseVector(Vec)
	return -Vec
end

And finally

A lot of unneeded stuff here, and this loop will run either once only or forever. Try

module.TrackRange = function(Part)
	if not Part then
		return
	end

	local Range = 100

	while task.wait() do
		for i, v in ipairs(workspace.GeneratedRooms:GetChildren()) do
			if (Part.Position - v.PrimaryPart.Position).Magnitude < Range and not HasTag(v, "Generated") then
				module.Generate(v)
			else
				break
			end
		end
	end
end

This immediately stops when the room is too far away or is tagged with “Generated”. I’m fairly sure that won’t be what you need, but I got a question, why do you have a while loop? I think the for loop alone is enough (and without any breaks), so:

module.TrackRange = function(Part)
	if not Part then
		return
	end

	local Range = 100

	for i, v in ipairs(workspace.GeneratedRooms:GetChildren()) do
		if (Part.Position - v.PrimaryPart.Position).Magnitude < Range and not HasTag(v, "Generated") then
			module.Generate(v)
		end
	end
end

die the inverse vector, its liek that becasue it breaks how the tag system works when it puts -0 instead of jsut 0

1 Like

What would the difference be if it’s 0 or -0? Any math calculations will end up the same, no?

and the while loop is so it keeps generating when the player goes along, dont want it to generate only once

That means the function is only called once? If yes, then make sure to remove my break statement, then.

its not the math calculations its in the
if not HasTag(From,(“Generated”…tostring(offset))) then
if the number is -0 instead of 0 then it dosent detect it

inputing the things that dont go against what im looking for, dosent really help in the terms of the lag issue

its because of the for loop having to run through the generated rooms when theres alot of children in the folder

i do appreciate the other optimizations, but its not exactly what i need at the moment (yes i used them)

Well, after learning the issue in InverseVector, I still think there are some things to improve, and maybe this function is better?

local function InverseVector(Vec)
    return Vector3.new(
        Vec.X ~= 0 and -Vec.X or 0,
        Vec.Y ~= 0 and -Vec.Y or 0,
        Vec.Z ~= 0 and -Vec.Z or 0
    )
end

Away from that, you can save "Generated" .. tostring(offset) to a variable since it’s repeated twice, though I would assume that’s a very tiny optimization.


I can’t think of anything else now tbh.

Instead of writing faster code, i have to write smarter code

What does it mean? This beatifull quote by IGBLON simply tells that you shouldn’t generate chunks soo fast, you simply overload the game, instead generate them only when player needs to see them, you can store them in array and render them on client to improve performance even more

Also you should add some sort of rendering system, instead your game will be unplayable

This should’ve been code review category remember next time

the thing is with this, i need this to also work on the server for 1
and 2 the rooms are very open currently, so making a render system like that would be completely usless as there isnt even walls yet

wasent really sure where it should be, ill keep that in mind

It will work on server, but you will only store rooms inside table, also rendering can be done, you can adjust render to your own needs, for instance add fog and hide everything behind it

can you please explain what you mean with storing the “rooms” in a table?

Everything can be stored as data, example code that will generate 2D rooms grid without models, only data to recreate them

local Grid = 8 -- how many rows we want in each axis

local Rooms = {}

for i = 1, Grid ^ 2 do
    local index = (i - 1) -- we don't loop from 0 to Grid ^ 2 - 1 due to table being easier to use
    local x = index % Grid
    local z = math.floor(index / Grid)
    
    Rooms[i] = {
        x = x,
        z = z,
        index = index,
        id = "Room1" -- placeholder, you can create custom function that will pass room type
    } -- we storing room inside table
end

im not experienced in terms of data and tables, but ill see what i can do with a system like this

1 Like

it’s pretty much simpliest thing, everything is data in programming, and you can recreate everything based on data, in my example you can place rooms depending on x and z positions, i reccomend you look at chunk related stuff

im messing around with the chunk system thing, how would i make the system fit with rooms that are 25x25?

multiply x and z by number of studs you want them to be apart of each other