Help creating semi-realistic object-breaking physics

At the moment, I have a vase modeled along with 3 versions of it that are broken up into 7-9 different pieces. How I would go about visually breaking it into pieces? I assumed Roblox’s physics engine would be a bad method since it has so many pieces, but I tried that anyways because I’m not sure how to go about manually scripting it to break into pieces realistically.

The server script I have right now is very slow, but here it is:

local RS = game:GetService('ReplicatedStorage')

local initremote = RS:WaitForChild('VaseHandler') --remote that communicates with the server from a local script, indicating the player has thrown the object
local posremote = RS:WaitForChild('Position') --remote function which grabs the player's face direction
local debris = RS:WaitForChild('VaseBaseBreak1') --a version of the vase which is shattered into ~8 pieces
local potdupe = RS:WaitForChild('VaseDupe') --another clone of the vase which is what is used by the physics engine


initremote.OnServerEvent:Connect(function(plr, vase)
	local char = plr.Character or plr.Character:Wait()
	if char:WaitForChild('Torso'):FindFirstChild('VaseM6') then
		local prim = vase.BodyAttach  --vase primary part, solely for animation
		local part1 = vase.Cylinder --main vase meshpart 
		local part2 = vase["Cylinder.001"] 
		
		local running = false
		
		local clone = debris:Clone()
		local clone2 = potdupe:Clone()
		
		for i,v in pairs(clone:GetChildren()) do --loops through each broken vase part, setting a velocity that randomly archs upwards in a direction
			local mass = v.AssemblyMass
			v.AssemblyLinearVelocity = Vector3.new(mass * math.random(7, 15), mass * math.random(10, 20), mass * math.random(7, 15))
		end
		
		
		local force = 400
		local direction = posremote:InvokeClient(plr) + Vector3.new(0, 5, 0) --thrown endgoal position
		local cf = part1.CFrame
		vase:Destroy()
		clone2.Parent = workspace
		clone2:PivotTo(cf)  --moves the vase clone, replaces the vase the player is holding
		clone2:ApplyImpulse(direction * Vector3.new(force, force, force)) --vase throwing impulse thing
		
		
		clone2.Touched:Connect(function(object)
			if object.CanCollide == true and running == false and object.Parent ~= char then --touched event that I made trying to determine when the vase should break
				running = true
				
				local store = clone2.CFrame
				clone2:Destroy()
				clone.Parent = workspace
				clone:PivotTo(store) 
				
			end
		end)
		
		task.wait(0.4)
		part1.CanTouch = true --allows the touched event to be activated with a delay, so it doesn't collide with the player
	end
end)

For the most part, it works. BUUT… Changing the states of the parts so much and adding in new parts is creating a big delay I think? Could I have some suggestions/help on how to handle this kind of mechanic? I’m willing to try anything.

For reference, the old version of this script had both the shattered vase and the intact vase together, and it relied on destroying motor6Ds and changing transparency to make it seem like it broke the vase. This was also slow.

2 Likes

Use Actors, An actor runs in Parallel Luau,Actors Basics, An actor Instance Can house Scripts inside of it, Scripts Located inside of which Run in Parallel Luau Meaning You can have Multiple Loops running at once without the need to divide them in to separate threads, even if their is No Loops in Your Script parallel typical Run Faster With Less lag, BUT dont over use these, or use Them Just To mitigate a script with Strong Lag Unless you cant make it any less laggy, Their is also alot more to it you should look into it, Also Why The Hell Are you use Remote Events in This, This can be done completely in the server unless this is interlocked to some Deep in game occurrence this is completely unnecessary, I Mean why, Is this Related To a tool a user uses to brake them, then yeah this makes sense, and you can ignore this part

Using remote events to get better position info and to determine when the player has thrown the pot. Not sure how I’d handle all of it on the server as animation is involved a good bit. I’ll look into actors a bit, but for the most part your comment is hard to read :face_with_spiral_eyes:

I’ve looked into actors and parallel Luau, I don’t think it’s a great option… For the most part it seems like it is used for much more complex tasks, while all I’m trying to do is replace parts and give them velocity quickly. Do you think it would be possible to optimize my script fundamentally at all?

(do let me know if this IS something I should use Parallel Luau for)

Instead of creating a velocity for all the Vase parts, what happens if you apply the velocity to just the model, then destroy the welds between the Parts?
You could also use a small Explosion to destroy the welds and provide a force to push them outwards.

I’ll try these out and let you know how it goes :grin:

I tried the first method, and it still has a delay when I throw it and right when it breaks. Here is the script now:

local RS = game:GetService('ReplicatedStorage')

local initremote = RS:WaitForChild('VaseHandler')
local posremote = RS:WaitForChild('Position')
local debris = RS:WaitForChild('VaseBaseBreak1')


initremote.OnServerEvent:Connect(function(plr, vase)
	local char = plr.Character or plr.Character:Wait()
	if char:WaitForChild('Torso'):FindFirstChild('VaseM6') then
		local prim = vase.BodyAttach
		local part1 = vase.Cylinder
		local part2 = vase["Cylinder.001"]
		
		local running = false
		
		local clone = debris:Clone()
		local prim2 = clone:WaitForChild('VaseDupe')
		
		local force = 3000
		local direction = posremote:InvokeClient(plr) + Vector3.new(0, 0.1, 0)
		local cf = part1.CFrame
		vase:Destroy()    --destroys the vase attached to the player to replace it with the one that is thrown and broken
		clone.Parent = workspace
		clone:PivotTo(cf)
		prim2:ApplyImpulse(direction * Vector3.new(force, force, force)) 
		
		
		prim2.Touched:Connect(function(object)
			if object.CanCollide == true and running == false and object.Parent ~= char then
				running = true
				local store = prim2.CFrame
				prim2:Destroy()  --destroys the primarypart which has all the welds
				
			end
		end)
		
		task.wait(0.3)
		part1.CanTouch = true
	end
end)

I’m not sure how to send a video, but I can if you need me to

I think it comes down to all the welds breaking at once while it’s unanchored now that I’ve messed with it some more

I fixed it! It was an issue with network ownership. I’m not sure how secure it is because I relied on another remote that communicates with the client, giving it the velocity to move the vase, but it works and it’s MUCH more fluid than before. Thanks for the help, learned some new things.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.