How do I detect if a part is on a ledge?


How do I detect if a part is on a ledge, in real time, for parts, not humans?
And how can I get the part that is not on on ground (the half of the part that is on air)
I thought of raycasting, but it would take a whole lot of raycasting…

Raycast downwards from all four corners of the part, if one of the cast rays hits the floor (baseplate) the part must be on a ledge.

local Workspace = workspace
local Part = Workspace.Part

local function IsOnLedge(Part)
	local Corner1 = Part.Position + Vector3.new(Part.Size.X / 2, 0, Part.Size.Z / 2)
	local Corner2 = Part.Position + Vector3.new(-Part.Size.X / 2, 0, -Part.Size.Z / 2)
	local Corner3 = Part.Position + Vector3.new(Part.Size.X / 2, 0, -Part.Size.Z / 2)
	local Corner4 = Part.Position + Vector3.new(-Part.Size.X / 2, 0, -Part.Size.Z / 2)
	local Corners = {Corner1, Corner2, Corner3, Corner4}
	local Parameters = RaycastParams.new()
	Parameters.FilterDescendantsInstances = {Part}
	for _, Corner in ipairs(Corners) do
		local Direction = (Corner - (Corner + Vector3.new(0, 1, 0))).Unit
		local Result = Workspace:Raycast(Corner, Direction * 50, Parameters)
		if Result then
			if Result.Instance.Name == "Baseplate" then
				return true
			end
		end
	end
	return false
end

local Result = IsOnLedge(Part)
print(Result)

image

Result is ‘true’.

image

Result is ‘false’.

1 Like

This works, very well, and thank you so much, but there are a few glitches, like it sometimes returning true when it’s not close to a ledge, or it returning false when its even over a ledge. And is there a way to get the area of the part that is on air?

This works, very well, and thank you so much, but there are a few glitches

I should clarify that the implementation I wrote will not work with rotated parts and/or parts already on the floor.

1 Like
local Workspace = workspace
local Baseplate = Workspace.Baseplate --Reference to the 'floor' part.
local Part = Workspace.Part

local function IsOnLedge(Part)
	local Corner1 = Part.CFrame * CFrame.new(Part.Size.X / 2, 0, Part.Size.Z / 2)
	local Corner2 = Part.CFrame * CFrame.new(-Part.Size.X / 2, 0, -Part.Size.Z / 2)
	local Corner3 = Part.CFrame * CFrame.new(Part.Size.X / 2, 0, -Part.Size.Z / 2)
	local Corner4 = Part.CFrame * CFrame.new(-Part.Size.X / 2, 0, -Part.Size.Z / 2)
	local Corners = {Corner1, Corner2, Corner3, Corner4}
	local Parameters = RaycastParams.new()
	Parameters.FilterDescendantsInstances = {Part}
	local Results = {}
	for _, Corner in ipairs(Corners) do
		local Position = Corner.Position
		local Direction = (Position - (Corner * CFrame.new(0, 1, 0)).Position).Unit
		local Result = Workspace:Raycast(Position, Direction * 50, Parameters)
		if Result then
			local Distance = (Result.Position - Position).Magnitude
			if Result.Instance ~= Baseplate or Distance > Part.Size.Y / 2 then
				if not table.find(Results, Result.Instance) then
					table.insert(Results, Result.Instance)
				end
			end
		end
	end
	return if (table.find(Results, Baseplate) and #Results > 1) then true else false
end

local Result = IsOnLedge(Part)
print(Result)

Here’s an implementation which is compatible with rotated parts and parts already on the floor (baseplate).

image

Result is ‘true’.

image

Result is ‘false’.

image

Result is ‘false’.

image

Result is ‘true’.

image

Result is ‘false’.

2 Likes