**Handling leg loss and balance for custom multi-legged NPCs with IK on Roblox**

The problem I’m encountering is that when one or multiple legs are destroyed, the rig still remains upright instead of tipping or losing balance.

I haven’t found a solution yet because this issue is physics-based, and I believe the Humanoid’s HipHeight property will override any adjustments I try to make and I wasnt able to find any solutions on the creator hub.

For context, as you might have seen in the video, I’m testing IK control and creating procedural animations, which are working well so far. The final goal is to implement a balance system that allows the model to maintain stability and realistically fall over based on its own center of gravity.

Also this is the movement script im using to accomplish the leg movement.

local runService = game:GetService(“RunService”)

local enemy = script.Parent
local root = enemy:FindFirstChild(“HumanoidRootPart”)
local hum = enemy:FindFirstChildOfClass(“Humanoid”)
local target = workspace:FindFirstChild(“Target”)

local ikTargets = enemy:FindFirstChild(“IkTargets”)
local raycastParts = enemy:FindFirstChild(“RaycastParts”)
local alignOrientation = root:FindFirstChild(“AlignOrientation”)
local ProceduralModule = require(game.ReplicatedStorage:WaitForChild(“ProceduralModule”))
local RagdollModule = require(game.ReplicatedStorage:WaitForChild(“Ragdoll”))

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {enemy}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude

local legNames = {
“FrontLeftLeg”, “FrontRightLeg”, “MiddleLeftLeg”, “MiddleRightLeg”,
“BackLeftLeg”, “BackRightLeg”, “Back2LeftLeg”, “Back2RightLeg”
}

local legs = {}

for _, name in ipairs(legNames) do
local ikTarget = ikTargets:FindFirstChild(name .. “_IkTarget”)
local raycastPart = raycastParts:FindFirstChild(name .. “_RaycastPart”)
local ikControl = hum:FindFirstChild(name)
local pole = root:FindFirstChild(name .. “_Pole”)

if ikTarget and raycastPart and ikControl and pole then
	local health = ikControl:FindFirstChild("Health")
	if not health then
		health = Instance.new("NumberValue")
		health.Name = "Health"
		health.Value = 100
		health.Parent = ikControl
	end

	table.insert(legs, {
		name = name,
		ikTarget = ikTarget,
		raycastPart = raycastPart,
		ikControl = ikControl,
		pole = pole,
		enabled = true,
		health = health,
	})

	ikControl.Pole = pole
end

end

coroutine.wrap(function()
while task.wait(0.25) do
if target and target:IsDescendantOf(workspace) then
hum:MoveTo(target.Position)
end
end
end)()

runService.Heartbeat:Connect(function()
local rayCast = workspace:Raycast(root.Position, -1000 * root.CFrame.UpVector, raycastParams)
if rayCast then
local floorRot = ProceduralModule:getRotationBetween(root.CFrame.UpVector, rayCast.Normal)
local floorCFrame = floorRot * CFrame.new(root.Position)
local dz = (root.Position.Z - target.Position.Z)
local dx = (root.Position.X - target.Position.X)
local angle = math.atan2(dx, dz)
if alignOrientation and alignOrientation.Enabled then
alignOrientation.CFrame = floorCFrame.Rotation * CFrame.fromOrientation(0, angle, 0)
end
end
end)

runService.Heartbeat:Connect(function()
local totalY, activeLegs = 0, 0
local lowestY = math.huge
local highestY = -math.huge

for _, leg in ipairs(legs) do
	if leg.enabled then
		local y = leg.ikTarget.Position.Y
		totalY += y
		activeLegs += 1
		lowestY = math.min(lowestY, y)
		highestY = math.max(highestY, y)
	end
end

local align = root:FindFirstChild("StepAlign")
if align and activeLegs > 0 then
	local avgY = totalY / activeLegs
	local tiltAmount = (highestY - lowestY) / 4
	align.Position = Vector3.new(root.Position.X, avgY + 3 - tiltAmount, root.Position.Z)
end

end)

local phaseToggle = false
coroutine.wrap(function()
while task.wait(0.2) do
local stepData = {
[false] = {
{“BackLeftLeg”, -1.5, -3.6, 2}, {“BackRightLeg”, -1.5, -4.2, 2.4},
{“Back2LeftLeg”, -1.5, -4, 1.6}, {“Back2RightLeg”, -1.5, -4.4, 2.2},
{“FrontLeftLeg”, -1.5, 4, 4}, {“FrontRightLeg”, -1.5, -3, 2.4},
{“MiddleLeftLeg”, -1.5, -2.4, 2}, {“MiddleRightLeg”,-1.5, 3, 3},
},
[true] = {
{“BackLeftLeg”, -1.5, 4, 3}, {“BackRightLeg”, -1.5, 4.2, 3.2},
{“Back2LeftLeg”, -1.5, 4.2, 3.2},{“Back2RightLeg”, -1.5, 4.5, 3.5},
{“FrontLeftLeg”, -1.5, -3.6, 2}, {“FrontRightLeg”, -1.5, 4, 3},
{“MiddleLeftLeg”, -1.5, 3, 3}, {“MiddleRightLeg”,-1.5, -2.4, 2.2},
}
}

	for _, data in ipairs(stepData[phaseToggle]) do
		local legName, yOffset, zOffset, forward = unpack(data)
		for _, leg in ipairs(legs) do
			if leg.name == legName and leg.enabled then
				ProceduralModule:IkLegStep(leg.ikTarget, leg.raycastPart, root, yOffset, zOffset, forward, 0.05, raycastParams)
				break
			end
		end
	end

	phaseToggle = not phaseToggle
end

end)()