A core part of gameplay (for an upcoming game) is to stomp on buildings/ai’s and essentially “bully” them.
As you will see in this video that the building is made out of default bricks (4, 1, 2). When you use your ability, it raycasts (or however they do it) and gets all the parts hit and unanchors them, and applies a slight impulse on them. I have been able to figure most of it out, except that when the building can’t stand on its own, it falls down.
What I am confused about is how they detect that, or if they do something else.
Right now, all of the parts are anchored at runtime. I have tried to keep them unanchored, but they end up toppling over and the abilities are rendered useless as they can just push them.
What our game is doing:
Before I recorded, I stomped all of the building and it didn’t fall down due to the fact that the parts are anchored. That is pretty much my problem.
It seems that they don’t have the parts anchored because otherwise all of the building would fall apart, it seems to be held by welds or something, I can’t quite figure out what they are doing.
They probably just welded parts to the parts they’re touching and kept everything unanchored. That’s the easiest solution.
The harder solution would be to basically run a flood fill from each of the parts that are touching the parts you just removed, and mark any regions that aren’t connected to the ground. It would be a fun idea, but the first is a bit more practical.
Thanks for your reply! I have gone ahead and written a snippet of code I tested on a small model with default parts, I will update this if it works!
local lastPart
local function weld(part1, part2)
local wc = Instance.new("WeldConstraint", part1)
wc.Part0 = part1
wc.Part1 = part2
end
for _, child in ipairs(script.Parent:GetChildren()) do
if (child:IsA("BasePart")) then
if (lastPart ~= nil) then
weld(child, lastPart)
end
lastPart = child
end
end
Not too bad, but you might have unexpected welds between arbitrary parts—just because they’re next to each other in that loop doesn’t mean that they’re physically next to each other.
You can try just calling Model | Roblox Creator Documentation on the model but that method has been deprecated and might not work. I wish there was a replacement that used WeldConstraints.
As a final idea, you could write your own “GetTouchingParts” by creating a Region3 that’s slightly larger than the part itself, and then get all the parts inside that region.
Or if your parts are regularly spaced on a grid or something it’s much easier because you can just lookup on a grid.
I tried to comment it up a bit, let me know if you have any questions.
It’s also possibly not very fast, so don’t run it too often
-- creates a Region3 around a part which
-- is slightly larger than the part.
-- requires that the part be rotated only
-- in 90 degree increments
local function GetRegionFromPart(part, distance)
distance = distance or 0.05
-- remove 90 degree rotations in the size
-- in other words, get the size of the
-- part as if it weren't rotated
local size = part.CFrame:VectorToWorldSpace(part.Size)
size = Vector3.new(math.abs(size.X), math.abs(size.X), math.abs(size.X))
local offset = Vector3.new(distance, distance, distance)
local lower = part.Position - size/2 - offset
local upper = part.Position + size/2 + offset
return Region3.new(lower, upper)
end
-- creates a WeldConstraint for each pair
-- of touching parts in the model.
-- only works well if the parts are axis-
-- aligned (i.e. no 45 degree angles)
local function WeldTouching(model)
-- keep track of already welded
local welded = {}
local descendants = model:GetDescendants()
for _, child in pairs(descendants) do
if child:IsA("BasePart") then
welded[child] = true
local region = GetRegionFromPart(child)
for _, connected in pairs(workspace:FindPartsInRegion3WithIgnoreList(region, descendants)) do
-- don't double weld
if connected ~= child and not welded[connected] then
local weld = Instance.new("WeldConstraint")
weld.Part0 = child
weld.Part1 = connected
weld.Parent = child
end
end
end
end
end
-- example usage
WeldTouching(workspace.Model)