I will be showing you how you can make soft destruction in Roblox! When you try creating destruction, the part would always bounce back? This tutorial will prevent that and provide a smoother destruction system.
Video:
Code:
local RunService = game:GetService("RunService")
local model = script.Parent
local breakThreshold = 1 -- minimum impact speed
local previousVelocities = {} -- stores previous velocities so we can accurately get its velocity after impact
local function CalculateImpactCoefficient(direction, velocityDirection)
local dotProduct = velocityDirection:Dot(direction)
local reflectedVelocity = velocityDirection - 2 * dotProduct * direction
local coefficient = math.clamp(math.abs(reflectedVelocity:Dot(direction)), 0, 1)
return coefficient
end
local function HasJoints(part)
local joints = part:GetJoints()
for i,v in ipairs(joints) do
if v:IsA("WeldConstraint") then
return true
end
end
end
local function SetUp(part)
part.Touched:Connect(function(hit)
if HasJoints(part) then
local origin = part.Position
local velocity = previousVelocities[part] or part.AssemblyLinearVelocity -- get its previous velocity
local mass = part.AssemblyMass -- its total mass including parts connected to that part
local point = hit:GetClosestPointOnSurface(origin) -- the position on the part that's closest to the origin
local direction = (origin - point).Unit -- direction from the origin to the point
local otherVelocity = hit.AssemblyLinearVelocity
local otherMass = hit.AssemblyMass
local relativeVelocity = velocity - otherVelocity -- prevent breaking when moving in same direction with same speed
local coefficient = CalculateImpactCoefficient(direction, relativeVelocity.Unit) -- how much the part will bounce back
local massRatio = math.clamp((mass + otherMass) / mass - 1, 0, 1) -- more breakable when hit by a heavy object
local force = relativeVelocity.Magnitude * coefficient * massRatio -- calculate the force of the impact
if force >= breakThreshold then -- if the force is enough
local connectedParts = part:GetConnectedParts(true) -- get all parts connected to that part and parts connected to that other part
part:BreakJoints() -- break all part joints
local newVelocity = velocity * coefficient -- get the new velocity after impact
for i,v in ipairs(connectedParts) do
v.AssemblyLinearVelocity = newVelocity -- maintain its velocity so that it doesn't bounce back after impact
break -- we don't need to apply it more than once
end
end
end
end)
end
for i,v in ipairs(model:GetDescendants()) do
if v:IsA("BasePart") then
SetUp(v)
end
end
model.DescendantAdded:Connect(function(descendant)
if descendant:IsA("BasePart") then
SetUp(descendant)
end
end)
RunService.Stepped:Connect(function()
for i,v in ipairs(model:GetDescendants()) do
if v:IsA("BasePart") then
previousVelocities[v] = v.AssemblyLinearVelocity
end
end
end)