Gravity to build system

  1. I’m trying to make it so when a part under a part is destroyed it will make the floating parts fall down like in Creature CHAOS

  2. The blocks just float mid air

  3. Tried looking for solutions on the Developer Hub

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BlocksPlace = game.Workspace.Blocks

ReplicatedStorage.place.OnServerEvent:Connect(function(player, Positiona, Matpicked)
	if not ReplicatedStorage.Blocks:FindFirstChild(Matpicked) then
		warn("Material not found: " .. Matpicked)
		return
	end

	local shape = ReplicatedStorage.Blocks[Matpicked]:Clone()
	local tag = Instance.new("StringValue")
	tag.Name = "blockowner"
	tag.Value = player.Name
	tag.Parent = shape

	shape.Parent = BlocksPlace
	shape.Size = Vector3.new(3, 3, 3)
	shape.Anchored = true
	shape.CFrame = Positiona
end)

ReplicatedStorage.del.OnServerEvent:Connect(function(player, target)
	if target and target:IsA("BasePart") then
		target:Destroy()
	else
		warn("Invalid target for deletion")
	end
end)

If anyone knows how to do it please let me know how thanks!

5 Likes

You could make it so that any blocks placed on the ground are anchored and blocks placed on that are welded to that block. So you only anchor when the part is touching the ground. When deleting a part make sure to delete all welds attached to it. Then once the anchored part gets deleted the rest of the structure will fall. . . [I have not tested this but it should work in theory]

2 Likes

But won’t that make the parts on top that are welded fall if pushed?

1 Like

if you use a “WeldConstraint” it will make 2 parts be completly locked to eachother. If one block falls the whole thing falls so it will be very heavy and hard for a player to push around. and as long as the part at the bottom is anchored it wont fall

2 Likes

So if they do fall will they fall as if they were 1 part not a shower of parts coming down?

1 Like

yes

minimum characters neeeded aaaaaaaaaaaaaa

1 Like

Ok but i won’t really know how to make that lol

Im in school and my class starts now so ill give you a prototype script once its over

Alr Thank you so much!

roblox why this thing…

what?⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

I’m working on writing up something to assist you, I’ll send the code when I’m finished here. But ideally, I’d use raycasting to ensure the parts are on top of each other, which is what I’m writing for you with commentary to explain it.

1 Like

I’m excited to see what you’re cooking up!

Well I’m finished, (as far as I know)
This code should be functional.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BlocksPlace = game.Workspace.Blocks

local DistanceToCheckAbove = 25 --> Raycast will only go 25 studs up to check for parts before returning nil.
local DistanceToCheckSides = 10 --> Raycast will only go 10 studs (plus the size of the part to make it similar to casting from the edge)

ReplicatedStorage.place.OnServerEvent:Connect(function(player, Positiona, Matpicked)
	if not ReplicatedStorage.Blocks:FindFirstChild(Matpicked) then
		warn("Material not found: " .. Matpicked)
		return
	end

	local shape = ReplicatedStorage.Blocks[Matpicked]:Clone()
	local tag = Instance.new("StringValue")
	tag.Name = "blockowner"
	tag.Value = player.Name
	tag.Parent = shape

	shape.Size = Vector3.new(3, 3, 3)
	shape.Anchored = true
	shape.CFrame = Positiona
  shape.Parent = BlocksPlace --> Always parent things after you've applied all the initial properties
end)

local RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude
RayParams.IgnoreWater = true

local function RecursiveGetParts(Part) --> Recursively check if there's a part above the last
  local Parts = {} --> Make table to store the parts we find.
  local Current = Part --> Make a variable to store the current part we're casting from.
  local Result = nil --> Make a variable to store the RaycastResult (this helps with breaking the recursive loop)
  repeat
    RayParams.FilterDescendantsInstances = {Current} --> Update filter so we don't just get the same part each time.
    local Origin = Current.Position --> Current part position (we will raycast from this)
    local Direction = Vector3.new(0,DistanceToCheck,0) --> We want the ray to go vertically, or up, so we use 0,DistanceToCheck,0
    Result = workspace:Raycast(Origin, Direction, RayParams) --> Raycast from Origin, following Direction, and use our RaycastParams to filter the cast. Then store the result in our Result variable.
    if Result --> Ensure we did get a result from the Raycast.
      and Result.Instance --> Ensure the Raycast returned an object.
      and Result.Instance:IsA("BasePart") --> Ensure it's a BasePart (covers all Part types, such as MeshPart, Part, CornerWedge, etc)
      and Result.Instance:FindFirstChild("blockowner") --> Ensure it's a placed part (Has "blockowner" value)
      and not table.find(Parts, Result.Instance) --> Ensure we haven't already gotten this part.
      and not Result.Instance == Current --> Ensure the part we got was not our current part (should be impossible but this is a failsafe to prevent an infinite loop)
    then
      table.insert(Parts, Result.Instance) --> Insert the new part to the Parts storage table.
      Current = Result.Instance --> Set the next target (Current) to the part we got.
    else
      break --> In case any of our failsafes/checks go off, we should break the loop to prevent an infinite loop.
    end
  until Result == nil or (Result and Result.Instance == nil) --> If the Raycast does not return a result, or there is no Result.Instance, we break the loop.
  return Parts --> Return the parts list
end

local function CheckIfTouching(Part) --> Check if a part is touching any other parts
  RayParams.FilterDescendantsInstances = {Part} --> Update filter
  local Touching = false --> Cache Touching so we can set it later
  local Origin = Part.Position
  local Sides = { --> Define side directions
    Vector3.new(DistanceToCheckSides,0,0) + (Part.Size * Vector3.new(0.5,0,0)), --> Left
    Vector3.new(-DistanceToCheckSides,0,0) - (Part.Size * Vector3.new(0.5,0,0)), --> Right
    Vector3.new(0,0,DistanceToCheckSides) + (Part.Size * Vector3.new(0,0,0.5)), --> Front
    Vector3.new(0,0,-DistanceToCheckSides) - (Part.Size * Vector3.new(0,0,0.5)) --> Back
  }
  for _, Side in pairs(Sides) do --> Loop through Sides
    local Result = workspace:Raycast(Origin, Side, RayParams) --> Raycast with current side direction and our filter RayParams.
    if Result and Result.Instance and Result.Instance:IsA("Part") and Result.Instance:FindFirstChild("blockowner") then --> Same checks as in RecursiveGetParts, besides the checks for the Current part and table.find
      Touching = true --> We found a part that we're touching!
      break --> We don't need to continue through the rest of the sides.
    end
  end
  return Touching --> Return Touching as it tells us if it's touching or not.
end

local function GetPartsAboveNotTouching(part) --> Get all parts that are above the target AND actually floating (not touching another part) (This option is more intensive than the other function) (option 1)
  local List = RecursiveGetParts(part) --> The following code checks to see if the parts are actually floating (does not touch anything else)
  for Index, Part in ipairs(List) do --> Loop through all the parts
    if CheckIfTouching(Part) then --> Check if the part is touching something
      table.remove(List, Index) --> If it's touching, remove the part from the list.
    end
  end
  return List
end

local function GetPartsAbove(part) --> Get all parts that are above the target, regardless of if they are touching anything (option 2)
  return RecursiveGetParts(part) --> The following code checks to see if the parts are actually floating (does not touch anything else)
end

ReplicatedStorage.del.OnServerEvent:Connect(function(player, target)
	if target and target:IsA("BasePart") then
    local Floating = GetPartsAbove(target) --> You can use either GetPartsAbove(target) or GetPartsAboveNotTouching(target) to get these parts. GetPartsAboveNotTouching will be more performance heavy.
    -- Now that we've got all the floating parts, we can do something with them
    for _, Part in pairs(Floating) do
      Part.Anchored = false -- In this case, we'll just unanchor the part so it falls, you can make this do whatever you want.
    end
		target:Destroy()
	else
		warn("Invalid target for deletion")
	end
end)

Let me know if anything goes wrong, breaks, or otherwise does not work.
I’ve added comments to explain everything I changed and to explain the different options I added.

1 Like

1 Like

should i change the “DistanceToCheck” to “DistanceToCheckAbove” or “DistanceToCheckSides”

Oh my, I forgot to update that when I changed the variable name, It should be the Above variable.

and for this do i just leave it?
image

1 Like

It should just be a false positive, it should be fine. Let me know if it errors when you run it, though.

No errors in the output but it still floats.
image

So i removed the and not Result.Instance == Current and it worked but also what i want is the part that fall down to fall down like they are 1 part you can also do stuff like this
image