I’m working on a system for my Backrooms game to place parts randomly across an area. It’s almost complete, however the code to prevent parts from intersecting doesn’t work and the function to clear the parts freezes studio (Aside from that it does work though)
Here’s my code:
bases = {}
basesFolder = game.Workspace.bases
spawnsFolder = game.Workspace.spawn
-- Self explanatory variables
spawns = {}
minCount = 0 -- These 2 refer to minimum and maximum placements
maxCount = 0 -- These 2 refer to minimum and maximum placements
partCount = 0 -- Total parts in the folder, don't modify this
spawnedParts = {} -- FOlder to store spawned parts for debug purposes.
for i, v in ipairs(spawnsFolder:GetChildren()) do
spawns[i] = v
partCount += 1
print("Part ", i, "was added to list")
end
-- Add all the objects to spawn into a list
for i, v in ipairs(basesFolder:GetChildren()) do
bases[i] = v
print("Spawn base ", i, "was added to list")
end
-- Add all the spawn bases into a list
function randPlace(rotation, minRotation, maxRotation)
for i, v in bases do
minCount = v.minValue.Value
maxCount = v.maxValue.value
-- Get minimum and maximum spaned part counts.
maxX = v.Position.X + v.Size.X / 2
minX = v.Position.X - v.Size.X / 2
maxZ = v.Position.Z + v.Size.Z / 2
minZ = v.Position.Z - v.Size.Z / 2
-- Determines the edges of the base to prevent parts from generating outside
for i=1, math.random(minCount, maxCount) do
print(i)
-- Test print statement
place = spawns[math.random(1, partCount)]:Clone()
place.Parent = game.Workspace.spawned
maxX -= place.Size.X
minX += place.Size.X
maxZ -= place.Size.Z
minZ += place.Size.Z
-- Modify edges to prevent spawned parts from sticking out
-- Make a new random part
place.Position = Vector3.new(math.random(minX, maxX), place.Size.Y / 2 + v.Size.Y / 2, math.random(minZ, maxZ))
print(place.Position)
-- Debug print statement
if rotation then
place.Orientation = Vector3.new(0, math.random(minRotation, maxRotation), 0)
end -- Randomise rotation if it's enabled
place.Anchored = true
spawnedParts[i] = place
-- Add the new part to spawned parts, this lets the deletion function find it.
place.Touched:Connect(function(collision)
repeat
place.Position = Vector3.new(math.random(minX, maxX), place.Size.Y / 2 + v.Size.Y / 2, math.random(minZ, maxZ))
until collision == not game.Workspace.spawned:GetChildren()
end) -- make that thing work later
maxX += place.Size.X
minX -= place.Size.X
maxZ += place.Size.Z
minZ -= place.Size.Z
-- Reset edges
end
end
end
function reset()
for i in spawnedParts do
spawnedParts[i]:Destroy()
end
end
At the end of the script I also have it call the functions for debug purposes.
For the no intersecting feature I suggest to use GetBoundingBox of the models that you are cloning, in order to know how much space occupy, then, get a CFrame coordinate from your random function that is choosing a placement point within the base boundaries, then by using GetPartBoundsInBox you will use that CFrame coordinate and the BoundingBox size you got from the model to check that it can be placed without clipping with other parts within the same space, if false, retry, until the model is placed in a enough free space. Perfectly compatible with that the feature you want to include which could reorient the cloned models.
And the reason why studio freezes and a inreal game will freeze too, its because you are deleting many parts too fast. Just a add a task.wait() line on the iteration so it has enough time to complete the task, it will increase the total time a little but ensures there is no lag/freeze in game or studio
Then for the freezing could be any other thing in your approach.
What I can clearly see is that deleting many parts in a fast loop without task.wait() will cause freezing. Supposing you are deleting a bunch of parts
function reset()
for i in spawnedParts do
spawnedParts[i]:Destroy()
task.wait() -- this should help to avoid the freeze
end
end
Be sure to read the documentation… GetPartBoundsInBox() doesnt use a model.
You provide coordinates to that, the idea is to check if there is parts in that coordinate and box size.
Once you check if there are parts in there or not, you place the model.
So, with GetBoundingBox you get the area that your model occupy, then, with GetPartBoundsInBox using the size gotten from GetBoundingBox you will check if the random coordinate has enough room for your model to be placed. If none parts are inside the box you place the model, if it has parts inside the box you retry a different random coordinate, until it finds room or after a certain amount of retries
GetBoundingBox will return 2 values, the first one the CFrame of the Model, the second one the Size that the model occupy:
local modelCFrame, modelSize = Model:GetBoundingBox()
So you were trying to use GetPartBoundsInBox() from a CFrame (box variable), and you are not providing any parameter inside, as the random CFrame for the position to check and the size you obtained from GetBoundingBox of the model.
Quick example:
local Model = workspace:WaitForChild("Model"):Clone()
local modelCFrame, modelSize = Model:GetBoundingBox()
print("This is the size that the model occupy", modelSize)
local randomCFrame = CFrame.new(0,0,0) -- GET THE RANDOM POSITION INSIDE YOUR BASE
local objectsClippingThatSpace = workspace:GetPartBoundsInBox(randomCFrame, modelSize) -- CHECKING IF ARE OBJECTS IN THAT SPACE
warn("There are:", #objectsClippingThatSpace, "occupying that space")
if #objectsClippingThatSpace > 0 then
warn("retry with a new random CFrame inside the Base") -- until finding an empty spot
warn(objectsClippingThatSpace)
else
Model:PivotTo(randomCFrame) -- POSITION THE MODEL CAUSE THERE ARE NO PARTS OCCUPYING THE SPACE
end
You dont need to place the Model before you check if the space is clear, thats not efficient. First check the space using a random CFrame inside the Base, if its clear its when you place the Model, not before
You dont need to provide the boxFrame to GetPartBoundsInBox, only the boxSize. Its obvious that if you place the model first, that space is already occupied by the model itself
I mean, do not provide the CFrame that you got from GetBoundingBox(), the boxFrame do not use it… thats the CFrame where your original model is placed…
You need to provide a new random CFrame, the position where you want to place the model. workspace:GetPartBoundsInBox(randomCFrame, modelSize) -- RANDOM CFRAME NOT THE boxFrame
You better check carefully the example I provided on previous replies its pretty basic and easy to understand on its steps:
local Model = workspace:WaitForChild("Model"):Clone()
local modelCFrame, modelSize = Model:GetBoundingBox()
print("This is the size that the model occupy", modelSize)
local randomCFrame = CFrame.new(0,0,0) -- GET THE RANDOM POSITION INSIDE YOUR BASE
local objectsClippingThatSpace = workspace:GetPartBoundsInBox(randomCFrame, modelSize) -- CHECKING IF ARE OBJECTS IN THAT SPACE
warn("There are:", #objectsClippingThatSpace, "occupying that space")
if #objectsClippingThatSpace > 0 then
warn("retry with a new random CFrame inside the Base") -- until finding an empty spot
warn(objectsClippingThatSpace)
else
Model:PivotTo(randomCFrame) -- POSITION THE MODEL CAUSE THERE ARE NO PARTS OCCUPYING THE SPACE
end