Hi everyone, recently I’ve been trying to make a Voxel Destruction System. Atm it works so that when you click on a part, a Hitbox spawns at the Hit’s CFrame and destroys the part it hit, but it’s really laggy.
Here’s the code: (completely client sided for testing purposes and a little unorganized )
local pars = OverlapParams.new()
pars.FilterType = Enum.RaycastFilterType.Include
local children = {}
for _, Part in workspace.VoxelsFolder:GetDescendants() do
table.insert(children, Part)
end
pars.FilterDescendantsInstances = children
local MAX_SIZE = 5
local HALF_THRESHOLD = 1.5
local DESTROY_THRESHOLD = 1
local function IsSmaller(Part: Part)
if (Part.Size.X < (MAX_SIZE * DESTROY_THRESHOLD)) and (Part.Size.Y < (MAX_SIZE * DESTROY_THRESHOLD)) and (Part.Size.Z < (MAX_SIZE * DESTROY_THRESHOLD)) then
return true
end
return false
end
local function Destroy(Part: Part)
if IsSmaller(Part) == true then
Part:Destroy()
end
end
function GetCorner(part: Part)
local cf = part.CFrame
local size = part.Size
local corner
local frontFaceCenter = (cf + cf.LookVector * size.Z/2)
local bottomFrontEdgeCenter = frontFaceCenter - frontFaceCenter.UpVector * size.Y/2
corner = (bottomFrontEdgeCenter - bottomFrontEdgeCenter.RightVector * size.X/2)
return corner
end
local function ToHalf(Part: Part)
local SizeX = Part.Size.X
local SizeY = Part.Size.Y
local SizeZ = Part.Size.Z
local n = 2
local BiggestSide = math.max(SizeX, SizeY, SizeZ)
local Corner = GetCorner(Part)
if BiggestSide == SizeX then
for i = 1, n, 1 do
local PosX = SizeX / (2 * n) + (SizeX / n) * (i - 1)
local PosY = SizeY / 2
local PosZ = SizeZ / 2
local Position = Vector3.new(PosX, PosY, PosZ)
local NewPart = Part:Clone()
NewPart.Name = "Voxel"
NewPart.Parent = Part.Parent
NewPart.Size = Vector3.new(SizeX / n, SizeY, SizeZ)
NewPart.CFrame = Corner * CFrame.new(Position)
NewPart.Orientation = Part.Orientation
--NewPart.Color = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
table.insert(children, NewPart)
pars.FilterDescendantsInstances = children
end
elseif BiggestSide == SizeY then
for i = 1, n, 1 do
local PosX = SizeX / 2
local PosY = SizeY / (2 * n) + (SizeY / n) * (i - 1)
local PosZ = SizeZ / 2
local Position = Vector3.new(PosX, PosY, PosZ)
local NewPart = Part:Clone()
NewPart.Name = "Voxel"
NewPart.Parent = Part.Parent
NewPart.Size = Vector3.new(SizeX, SizeY / n, SizeZ)
NewPart.CFrame = Corner * CFrame.new(Position)
NewPart.Orientation = Part.Orientation
--NewPart.Color = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
table.insert(children, NewPart)
pars.FilterDescendantsInstances = children
end
elseif BiggestSide == SizeZ then
for i = 1, n, 1 do
local PosX = SizeX / 2
local PosY = SizeY / 2
local PosZ = SizeZ / (2 * n) + (SizeZ / n) * (i - 1)
local Position = Vector3.new(PosX, PosY, PosZ)
local NewPart = Part:Clone()
NewPart.Name = "Voxel"
NewPart.Parent = Part.Parent
NewPart.Size = Vector3.new(SizeX, SizeY, SizeZ / n)
NewPart.CFrame = Corner * CFrame.new(Position)
NewPart.Orientation = Part.Orientation
--NewPart.Color = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
table.insert(children, NewPart)
pars.FilterDescendantsInstances = children
end
end
Part:Destroy()
end
local function Voxelize(Part: Part, Hitbox: Part)
ToHalf(Part)
local TouchingParts = workspace:GetPartsInPart(Hitbox, pars)
if #TouchingParts > 0 then
for _, Part in TouchingParts do
if IsSmaller(Part) then
Destroy(Part)
continue
end
Voxelize(Part, Hitbox)
end
end
end
local RunService = game:GetService("RunService")
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local rootPart = char:WaitForChild("HumanoidRootPart")
local Mouse = plr:GetMouse()
local function CreateHitbox(cf: CFrame)
local Hitbox = Instance.new("Part")
Hitbox.Parent = workspace
Hitbox.Shape = Enum.PartType.Ball
Hitbox.Transparency = 0.7
Hitbox.Size = Vector3.new(15,15,15)
Hitbox.CanCollide = false
Hitbox.Anchored = true
Hitbox.Material = Enum.Material.SmoothPlastic
Hitbox.CFrame = cf
return Hitbox
end
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
if Target then
local TargetCFrame = Mouse.Hit
local Hitbox = CreateHitbox(TargetCFrame)
local TouchingParts = workspace:GetPartsInPart(Hitbox, pars)
if #TouchingParts > 0 then
for _, Part in TouchingParts do
if IsSmaller(Part) then
Destroy(Part)
continue
end
Voxelize(Part, Hitbox)
end
end
Hitbox:Destroy()
end
end)
Basically, when you click on a part, it gets subdivided in half based on the longest side, and it gets recursively subdivided again until it reaches MAX_SIZE and gets destroyed. I’ve also tried Octree Partitioning, but it gave me the same result as this “Half Partitioning”. Am I doing something wrong?
Any help is highly appreciated, thanks!