VoxelDestruct | Voxelated destruction physics with greedy meshing, hitboxes, and more!

offload the debris to client and do whatever to remove them on the server
dats how u fix the stutter for everyone

dude, why not make an testing open-source place so i can understand better this module?
edit:nevermind, i made it work after 2 hours

What about the slice module that cut the part/mesh into half or even into pieces but I don’t even see any slice examples on the topic?

hey dude, can you provide a test file for the successful result you had? i myself am not able to figure out how to use this thing either lol

Compared to VoxBreaker how is this better?

Only better part is more efficent algorithm for voxelizing

1 Like

Is it possible to get rid of these extremely thin parts? Not sure if grid lock even does anything…
image

I never said it was better nor did I intend for it to be made a comparison like that. It uses a different algorithm, has a queue, and greedy meshes. Thats how its different from VoxBreaker.

Whether or not it is better is debatable and in my opinion irrelevant as both modules provide unique and useful methods.

2 Likes

I put any example in this thread for a reason.

local vox = require(game:GetService("ReplicatedStorage"):WaitForChild("VoxelDestruction"))
local fling = 500

local unitSize = 20
local size = Vector3.new(unitSize, unitSize, unitSize)
local shape = Enum.PartType.Ball
local parameters = nil
local voxelSize = 0
local debrisCount = math.random(3,5)
local cutoutSize = 1
local gridLock = false
local reset = 5
local freeze = nil
local destroy = nil
local lock = nil

game:GetService("ReplicatedStorage"):WaitForChild("VoxelRemote").OnServerEvent:Connect(function(player, position)
	
	local debris, walls = vox.destroy(
		CFrame.new(position),
		size,
		shape,
		parameters,
		voxelSize,
		debrisCount,
		cutoutSize,
		gridLock,
		reset,
		freeze,
		destroy,
		lock
	)
	
	if #debris > 0 then
		for i,debri in ipairs(debris) do
			debri.Anchored = false; debri:SetNetworkOwner(nil)
			debri:ApplyImpulse( Vector3.new(math.random(-fling, fling), fling / 2, math.random(-fling, fling)) )
		end

		task.wait(5)
		vox.cleanup(debris)
	end
end)

Its very simple, require the model and use a function with the parameters it specifies. This thread includes a description for all of the parameters of each method. If your code does not work post a reply here with the code and whatever your output window says.

This is one of the concerning bugs that I thought I had gotten rid of? Would you please send me the model you’re using this on, whichever one is in that picture. I cannot reproduce this issue as its appearance is rare for me.

Also provide the code you’re using if you can.

Hey, sure thing.
House.rbxm (12.1 KB)
This is the model for the house.

And this is the code I am using to run the module.

local VoxelDestruction = require(Modules.VoxelDestruction)

local VoxelManager = {}

local DefaultResetTime = 60

function VoxelManager:MakeVoxels(Hitbox : Part,MoveAwayPos,Speed, ResetTime)
	local Size = Hitbox.Size
	local Position = Hitbox.CFrame
	local SizeMagnitude = Size.Magnitude
	local VoxelSize = math.ceil(SizeMagnitude / 4)
	local Shape = Hitbox.Shape
	ResetTime = ResetTime or DefaultResetTime
	--SendVoxelDataEvent:FireAllClients(Size,Position,VoxelSize,MoveAwayPos,Speed)
	local Voxels, walls = VoxelDestruction.destroy(
		Position,
		Size,
		Shape,
		OverlapParams.new(),
		VoxelSize,
		nil,
		1,
		nil,		
		ResetTime,
		nil,
		nil,
		nil
		
	)
	local Velocity = Vector3.zero
	local VoxelSounds = {}
	for _, Voxel : BasePart in pairs(Voxels) do
		Voxel:SetNetworkOwner(nil)
		--Voxel.Size *= 0.98
		if MoveAwayPos ~= nil then
			Velocity = (Voxel.Position - MoveAwayPos).Unit * Speed * Voxel:GetMass()
			local BodyVelocity = Instance.new("BodyVelocity")
			BodyVelocity.Velocity = Velocity
			BodyVelocity.Parent = Voxel
			Debris:AddItem(BodyVelocity,0.25)
		end
		if not table.find(VoxelSounds,Voxel.Material.Name) then
			table.insert(VoxelSounds,Voxel.Material.Name)
		end
		task.delay(ResetTime,function()
			VoxelDestruction.cleanup(Voxel)
		end)
	end
	for _, Sound in pairs(VoxelSounds) do
		local SoundFolder = script.Sounds:FindFirstChild(Sound)
		if SoundFolder then
			local PlaySound
			if Velocity.Magnitude < 30 then
				PlaySound = SoundFolder:FindFirstChild("LowVel"):Clone()
			else
				PlaySound = SoundFolder:FindFirstChild("LowVel"):Clone()
			end
			if PlaySound then
				PlaySound.Parent = Voxels[1]
				PlaySound:Play()
				Debris:AddItem(PlaySound,10)
			end
		end
	end
end

return VoxelManager

the reason i didn’t use this example is because it doesnt fit really well into my game, but i’ll try to edit it enough
thanks

Wow great updates man, everything is working great!!!

Hello! Awesome module you have written, it has a lot of promise! I noticed that when calling the destroy function I seem to get a strange split of parts, resembling tiny fragments.

I could see in the above thread that this is obviously not intentional, but here is my function call for reference

destruction.destroy(part.CFrame,part.Size,Enum.PartType.Block,nil,0,0,1,false,nil,false,false,false)

Thank you so much for this resource again.

Edit: By the way, these bricks are 4, 5, 0.75 in size, and for some strange reason this is constantly occuring. Side note, do you know how to keep the debris or parts from deleting? I set the resetMinimum in settings, but that doesn’t seem to affect the cleanup time, and I don’t feel like hard-coding that into your existing script.

Edit Edit: One last image for the road

Yo, can you make a testing game for VoxelDestruct? I’d like to test the module.

Would you be willing to send the settings you are using?

Could you please provide the settings you are using? I’m thinking this is just a result of having Settings.useGreedyMeshing set to false, I cannot reproduce this issue while this setting is set to true.

local Settings = {}

Settings.attribute = "Breakable" -- Name of attribute to check for
Settings.debrisContainer = workspace.Voxels -- Debris storage

Settings.resetDefault = 5 -- Time it takes for the wall to repair itself since last break
Settings.resetMinimum = 5 -- Minimum reset timer, passing a value less than this will use this

Settings.shapeDefault = Enum.PartType.Ball -- Default region shape
Settings.voxelDefault = 2 -- Default voxel size
Settings.debrisAnchored = false -- Whether or not debris are anchored by default
Settings.cutoutDefault = 1 -- Default cutout size
Settings.gridLockDefault = true -- Default grid lock, 

Settings.useRelativity = false -- If true relativity will be applied instead of default size when size is not specified
Settings.voxelRelative = 1/1.5 -- Voxel size relative to hitbox size
Settings.voxelMinimum = 3 -- Minimum voxel size
Settings.hitboxRelative = 1 -- If voxel size is not specified hitboxes will use a relative size applied to the part size
-- *this only applies to movement, to have your intersection sizes match your part size keep this at 1

Settings.useGreedyMeshing = true -- Recommended to leave this on for reduced part count to combat lag
Settings.useRunService = true -- Use RunService instead of detecting changed position, may be more accurate
Settings.usePartCache = true -- Use PartCache so instancing parts does not create lag
Settings.cachePrecreated = 10000 -- The original cache ceiling
Settings.cacheExtra = 100 -- The amount of extra parts created everytime the cache ceiling is reached

return Settings

Dumb question, but how did you get the affected parts to be unanchored instead of just destroyed in the showcase video? I played around with the module for a bit, but I’m still not very sure how to use it. Would it be possible to provide a testing place?

it worked, but not what i expected. Maybe i did something wrong, the whole construction has broken, not only the area i wanted. So, i think this i still didnt figured how to use this (but i hella want know how to use this thing)