VoxBreaker | An OOP Voxel Destruction module

how would i stop the parts from regenerating and just make it so they disappear after the timeToDestroy thingy?

2 Likes

when i handle voxels on the client using :CreateHitbox
and then destroy the voxels on the server it starts make duplicates of whats remaining of the part destroyed

so then whenever i try to destroy it on the client again, itll duplicate the amount of voxels

1 Like

how do i get it to play audio when its broken

1 Like

Is this way better than voxbreaker??? And can it be handled well in the server like jjs?

1 Like

I wouldn’t say its ‘better’ than VB since any kind of voxel destruction tools on roblox are a great step in the right direction.

It is very performant though if that is what you’re asking, at least if you dont go overboard with it. It has features like greedy meshing and part cache to help reduce part count and make it run smoothly on the server. I mean with any large amount of parts created quickly you will have lag, but theres features for making your voxel and debris sizes relative to compensate for that.

Any tool like this is going to have some lag, mine reduces it as much as possible using the same techniques in JJS but it won’t be enough to compensate for your games lag if you don’t use it mindfully.

1 Like

Finally got around to releasing it and making a page for it, but then the mods had to be vultures and close the thread before I had time to make all my changes. :man_facepalming:

Hope its fine if I post it here, I’d like to see it used successfully.

2 Likes

how should i make a hitbox that follows the player performant

because each time, i use moveable hitbox and just make it unanchor every voxel caught in the hitbox and that always ends up lagging a lot if i ever hit the ground unless i raise the voxel size above something like 4 or 5

1 Like

its ran on the server

1 Like

You’ll have to share your usage of this function, as well as what your code looks like on the client.

1 Like

whenever i try to voxelize a single part with partcache on it returns a error. (server)

	local VoxBreaker = require(game.ReplicatedStorage.Modules.VoxBreaker)		
    local vox = VoxBreaker:VoxelizePart(game.Workspace.PART, 5, 3)
ReplicatedStorage.Modules.VoxBreaker.PartCache:141: Attempted to return part "Breakable" (Workspace.Placee.Breakable) to the cache, but it's not in-use! Did you call this on the wrong part?

i also get errors like these from voxelizing parts in a model (server) – Not home rn so code below may be from a old script

local VoxBreaker = require(game.ReplicatedStorage.Modules.VoxBreaker)		

for i,v in pairs(game.Workspace.Train:GetChildren()) do
	if v:IsA("Part") then
		local voxelize2 = VoxBreaker:VoxelizePart(v, 5, 3)
	end
end
The Parent property of Part is locked, current parent: NULL, new parent VoxelHolder 
ReplicatedStorage.Modules.VoxBreaker:443: attempt to index nil with 'IsA'
1 Like

Some of the big parts or the outer parts are being counted somehow as a debris.
Is there any fix for this since its pretty annoying
image

2 Likes

Yeah this is a bug. Theres a few other issues that i will be fixing in the next update as well.

2 Likes

for some reason the table of the dissected parts return nil, any clue to why this is? The hitboxes do get created, that I am sure of, because the parts light up. However the part doesn’t get voxelated.

1 Like

Resolved, forgot to add attribute ‘Destroyable’

2 Likes

I’m having an issue with starting moveable hitboxes right now. Error : 12:12:41.498 ReplicatedStorage.Modules.VoxBreaker:1231: attempt to index nil with ‘Part’ - Client - VoxBreaker:1231 .
Here is the localscript that is running VoxBreaker :

local voxBreaker = require(game:GetService("ReplicatedStorage").Modules.VoxBreaker)
local event = game:GetService("ReplicatedStorage").Events.DestructionClient

local function shuffleTable(t)
	print("Shuffling table...")
	local n = #t
	for i = n, 2, -1 do
		local j = math.random(i)
		t[i], t[j] = t[j], t[i]
	end
end

local function onEvent(player, force, velocityTime, size, cframe, shape, minimumVoxelSize, destroyPercent, weldToPart)
	print("Received destruction event for player:", player.Name)
	if not weldToPart or weldToPart == nil then
		local character = player.Character
		local parts = voxBreaker:CreateHitbox(size, cframe, shape, minimumVoxelSize)
		print("Created hitbox parts:", #parts)

		-- Create a table of indices and shuffle it
		local indices = {}
		for i = 1, #parts do
			table.insert(indices, i)
		end
		shuffleTable(indices)

		-- Destroy 50% of the parts
		local destroyCount = math.floor(#parts / destroyPercent)
		print("Destroying", destroyCount, "parts out of", #parts)
		for i = 1, destroyCount do
			local partIndex = indices[i]
			parts[partIndex]:Destroy()
			print("Destroyed part", i, "with index", partIndex)
		end

		-- Add BodyVelocity to the remaining parts
		for i, v in pairs(parts) do
			if v.Parent then -- Check if the part was not destroyed
				v.Anchored = false
				local bv = Instance.new("BodyVelocity", v)
				bv.Velocity = character.HumanoidRootPart.CFrame.LookVector * force
				bv.MaxForce = Vector3.new(99999, 99999, 99999)
				bv.Name = "Velocity"
				game:GetService("Debris"):AddItem(bv, velocityTime)
				print("Added BodyVelocity to part:", v.Name)
			else
				print("Part", v.Name, "was destroyed before adding BodyVelocity")
				return
			end
		end
	end
	if weldToPart and weldToPart ~= nil then
		local character = player.Character
		local parts = voxBreaker.CreateMoveableHitbox(minimumVoxelSize, 50, size, weldToPart.CFrame, shape)
		parts.Start()
		print("started")
		parts.WeldTo(weldToPart)
		print("welded")
		print("Created movable hitbox parts:", #parts)
		
		if not weldToPart.Parent then
			parts.Stop()
			parts.Destroy()
			print("voxelbreaker destroyed early")
		end

		-- Create a table of indices and shuffle it
		local indices = {}
		for i = 1, #parts do
			table.insert(indices, i)
		end
		shuffleTable(indices)

		-- Destroy 50% of the parts
		local destroyCount = math.floor(#parts / destroyPercent)
		print("Destroying", destroyCount, "parts out of", #parts)
		for i = 1, destroyCount do
			local partIndex = indices[i]
			parts[partIndex]:Destroy()
			print("Destroyed part", i, "with index", partIndex)
		end

		-- Add BodyVelocity to the remaining parts
		for i, v in pairs(parts) do
			if v.Parent then -- Check if the part was not destroyed
				v.Anchored = false
				local bv = Instance.new("BodyVelocity", v)
				bv.Velocity = character.HumanoidRootPart.CFrame.LookVector * force
				bv.MaxForce = Vector3.new(99999, 99999, 99999)
				bv.Name = "Velocity"
				game:GetService("Debris"):AddItem(bv, velocityTime)
				print("Added BodyVelocity to part:", v.Name)
			else
				print("Part", v.Name, "was destroyed before adding BodyVelocity")
				return
			end
		end
	end	
end

event.OnClientEvent:Connect(onEvent)
print("Connected onEvent function to client event:", event.Name)

Does anyone have any ideas on how to fix?

EDIT: YOU CAN FIX IT BY DOING

parts:Start()
parts:Stop()
parts:Destroy()
--Instead of doing
parts.Start()
parts.Stop()
parts.Destroy()

@Bartokens is there a way to make the module destroy the parts of the main part clean it up but not reset the main part

You mean to not reset the part after a duration? You would do this by just setting reset time to -1 or any number below zero

no like don’t reset specific parts with stuff in them i have this building mechanic and if you destroy them they wouldn’t reset used with a diff voxel module but i like the parts flying out of this module and destroying themselves after a period of time.

easier terms if it has a value in the part that gets destroyed → it doesnt reset except for the little voxel parts

So in other words you want the voxels to be reset but not the original part? I mean an easy way to do this would be to just set the reset time to below zero, and then destroy the voxels manually