I’ve been wanting something like this for years. Thanks for the early release.
A developer @Lauri9 (view roblox profile) has worked on a quick demo, using this, which took only 3 hours(!!) to code and the results are promising!
AMAZING, I can’t wait to see what people do with this.
ive literally just made my entire map destructible i thank you
This is awesome!
What prevents this from being done on the client? The current solver is really fast and has little errors, especially compared to the old solver. This would reduce the network usage, and load much faster on the client.
Wrote a script that replicates the fragmenting parts shown off at RDC.
The secret is recursive plane cuts.
local fragmentPart = Instance.new("BindableEvent")
local tau = math.pi * 2
local function rollAngles(count)
local result = {}
for i = 1,count do
result[i] = math.random() * tau
end
return unpack(result)
end
local function subtract(part, negativePart, collisionFidelity)
if part:IsDescendantOf(workspace) then
local subtractor = {negativePart}
return part:SubtractAsync(subtractor, collisionFidelity)
end
end
local function onFragmentPart(part, depth)
if not part:IsDescendantOf(workspace) then
return
end
local depth = depth or 0
if depth > 4 then
return
end
local size = part.Size
if size.X < 1 or size.Y < 1 or size.Z < 1 then
return
end
local magnitude = size.Magnitude
if magnitude < 6 then
return
end
local cf = part.CFrame
local rx,ry,rz = rollAngles(3)
local cutPlane = cf * CFrame.Angles(rx, ry, rz)
local cut0 = Instance.new("Part")
cut0.Size = size*4
cut0.CFrame = cutPlane * CFrame.new(0,-size.Y*2,0)
local cut1 = cut0:Clone()
cut1.CFrame = cutPlane * CFrame.new(0,size.Y*2,0)
local part0, part1
pcall(function ()
part0 = subtract(part, cut0, "Hull")
part1 = subtract(part, cut1, "Hull")
end)
if part0 and part1 then
local parent = part.Parent
local velocity = part.Velocity
local rotVel = part.RotVelocity
part:Destroy()
local c0 = cf:toObjectSpace(part0.CFrame)
part0.CFrame = part.CFrame * c0
part0.Velocity = velocity
part0.RotVelocity = rotVel
part0.Parent = parent
local c1 = cf:toObjectSpace(part1.CFrame)
part1.CFrame = part.CFrame * c1
part1.Velocity = velocity
part1.RotVelocity = rotVel
part1.Parent = parent
-- Recursively fragment
fragmentPart:Fire(part0, depth+1)
fragmentPart:Fire(part1, depth+1)
end
end
local function onDescendantAdded(desc)
if desc:IsA("Explosion") then
local hasHit = {}
local function onExplosionHit(hit)
if not (hasHit[hit] or hit.Anchored or hit:FindFirstChildWhichIsA("FileMesh")) then
hasHit[hit] = true
fragmentPart:Fire(hit)
end
end
local hitSignal = desc.Hit:Connect(onExplosionHit)
delay(3,function ()
-- Garbage collect after the explosion is gone.
hitSignal:Disconnect()
hasHit = nil
end)
end
end
fragmentPart.Event:Connect(onFragmentPart)
workspace.DescendantAdded:Connect(onDescendantAdded)
Been playing with this and made a sword that slices parts.
Hiya - I keep receiving an error code 21 when testing CSG.
Here’s the test place.
Error Code 21 - CSG.rbxl (13.7 KB)
You’re creating the part on the client, which you’re passing to the server via remote. Since this part is created by the client, it isn’t replicated and the server just sees nil.
Instead of passing the part to the server, just pass the position where the player clicked and create the part on the server.
Pew pew pew! Unfortunately, the polygon count is excessive even for simple shapes. Those four little dents maxed out on the triangle limit.
Try using cylinders?
Use a cube and claim it’s for style and not because of technical limitations B-)
But srsly CSG isnt built for bullet holes in a production game.
You could use even less complex shapes without it being super noticeable by using a pyramid shape:
Oh my!
This is an excellent change. This is amazing!
Getting some pretty funky results when using UnionAsync to union more than two parts.
Here’s a reproduction for anyone interested:
UnionAsync Oddities.rbxl (15.3 KB)
This seems to be yielding a lot for me? I’m not sure if I’ve called it wrong, or too often, but it doesn’t do anything to the parts I specify and it doesn’t error; presumably it’s yielding as it doesn’t print what’s after the pcall. The same line of code worked earlier so I’m going to assume there’s some kind of rate limit that results in yielding or the error messages aren’t complete yet?
success, fault = pcall(function()
print("Subtracting")
newBase = baseplate:SubtractAsync({leftFoot, rightFoot})
print("Subtracted")
end)
‘Subtracted’ doesn’t get outputted and the prints following the pcall don’t show.
This actually only seems to happen in play solo
I managed to make a really crappy, extremely laggy footprint thing. Can’t wait until this is clientsided and I can do this properly
function makeParts(parts)
local createdParts = {}
for i = 1, #parts do
local newPart = Instance.new("Part")
newPart.Size = parts[i].Size + Vector3.new(0,0.75,0)
newPart.Position = parts[i].Position
newPart.Color = parts[i].Color
newPart.Anchored = true
newPart.Name = parts[i].Name
newPart.CanCollide = false
createdParts[i] = newPart
end
return createdParts[1], createdParts[2]
end
function monitorMovement(char)
local db = true
repeat wait() until char:FindFirstChild("Humanoid") ~= nil
char.Humanoid.Touched:Connect(function(part)
if char.Humanoid.FloorMaterial ~= Enum.Material.Air and db then
db = false
spawn(function()
wait(0.5)
db = true
end)
spawn(function()
print(char.Humanoid.FloorMaterial)
local leftFoot, rightFoot = char:FindFirstChild("LeftFoot"), char:FindFirstChild("RightFoot")
if leftFoot ~= nil and rightFoot ~= nil then
local newPart,success,fault
-- since meshparts aren't accepted, create parts to simulate the feet
leftFoot, rightFoot = makeParts({leftFoot, rightFoot})
-- do the editing
success, fault = pcall(function()
print("Subtracting", part:GetFullName(), leftFoot:GetFullName(), rightFoot:GetFullName())
newPart = part:SubtractAsync({leftFoot, rightFoot}, Enum.CollisionFidelity.Hull)
print("Subtracted")
end)
newPart.UsePartColor = false
print("Worked ig")
if success then
print("Making new baseplate")
newPart.Name = "AddedFootprint"
newPart.Parent = game.Workspace
wait(0.1)
part:Destroy()
else
print("Something went wrong")
print(fault)
end
-- remove created parts
leftFoot:Destroy()
rightFoot:Destroy()
end
end)
end
end)
end
game.Players.PlayerAdded:Connect(function(plr)
repeat wait() until plr.Character ~= nil
print("Character loaded")
spawn(function() monitorMovement(plr.Character) end)
plr.CharacterAdded:Connect(function(char)
monitorMovement(char)
end)
end)
I was waiting for this update for a long time especially to do this!