Hello. This is my first devforum post (yay)
I am struggling with getting a dead NPC ragdoll to stay in ragdoll and not stand up right. So far I have gotten closer to the fix, but it still manages to stand up.
The code I’m willing to share:
function setupJoints(character)
for i, motor6D in ipairs(character:GetDescendants()) do
local r = character.PrimaryPart:FindFirstChild("Root")
if r then
r:Destroy()
end
if motor6D:IsA("Motor6D") and motor6D.Part0.Name ~= "HumanoidRootPart" then
local attach0 = Instance.new("Attachment")
local attach1 = Instance.new("Attachment")
local ballSocket = Instance.new("BallSocketConstraint")
local noCollision = Instance.new("NoCollisionConstraint")
local isRoot = motor6D.Part0 == character.PrimaryPart
ballSocket.Name = "HumanJoint"
if not isRoot then
ballSocket.LimitsEnabled = true
ballSocket.TwistLimitsEnabled = true
ballSocket.Restitution = 0.1--0.678--.567--.843
end
ballSocket.Attachment0 = attach0
ballSocket.Attachment1 = attach1
ballSocket.Parent = motor6D.Part0
attach0.CFrame = motor6D.C0
attach1.CFrame = motor6D.C1
attach0.Parent = motor6D.Part0
attach1.Parent = motor6D.Part1
attach0.Name = "Attachment0Ragdoll"
attach1.Name = "Attachment1Ragdoll"
noCollision.Name = motor6D.Part0.Name.."And"..motor6D.Part1.Name
noCollision.Part0 = motor6D.Part0
noCollision.Part1 = motor6D.Part1
noCollision.Parent = motor6D.Part0
if motor6D.Name == "LeftKnee" then
local leftKnee = Instance.new("HingeConstraint")
motor6D.Part0:FindFirstChild("HumanJoint"):Destroy()
leftKnee.Name = "Knee"
leftKnee.Attachment0 = attach0
leftKnee.Attachment1 = attach1
leftKnee.Parent = motor6D.Part0
leftKnee.LimitsEnabled = true
leftKnee.UpperAngle = -10
leftKnee.LowerAngle = -135
leftKnee.AngularResponsiveness = 0.5
elseif motor6D.Name == "RightKnee" then
local rightKnee = Instance.new("HingeConstraint")
motor6D.Part0:FindFirstChild("HumanJoint"):Destroy()
rightKnee.Name = "Knee"
rightKnee.Attachment0 = attach0
rightKnee.Attachment1 = attach1
rightKnee.Parent = motor6D.Part0
rightKnee.LimitsEnabled = true
rightKnee.UpperAngle = -10
rightKnee.LowerAngle = -135
rightKnee.AngularResponsiveness = 0.5
elseif motor6D.Name == "LeftHip" then
ballSocket.UpperAngle = 60
ballSocket.TwistLowerAngle = -3
ballSocket.TwistUpperAngle = 3
elseif motor6D.Name == "RightHip" then
ballSocket.UpperAngle = 60
ballSocket.TwistLowerAngle = -3
ballSocket.TwistUpperAngle = 3
elseif motor6D.Part0.Name == "LowerTorso" then
ballSocket.UpperAngle = 15
ballSocket.TwistUpperAngle = 1
ballSocket.TwistLowerAngle = -1
elseif motor6D.Part0.Name == "UpperTorso" then
ballSocket.UpperAngle = -10
elseif motor6D.Name == "LeftAnkle" or motor6D.Name == "RightAnkle" then
local hinge = Instance.new("HingeConstraint")
motor6D.Part0:FindFirstChild("HumanJoint"):Destroy()
hinge.Attachment0 = attach0
hinge.Attachment1 = attach1
hinge.Parent = motor6D.Part0
hinge.LimitsEnabled = true
hinge.UpperAngle = 0
hinge.Restitution = 0
hinge.LowerAngle = -45
hinge.AngularResponsiveness = 0.5
elseif motor6D.Name == "LeftWrist" or motor6D.Name == "RightWrist" then
local hinge = Instance.new("HingeConstraint")
motor6D.Part0:FindFirstChild("HumanJoint"):Destroy()
hinge.Attachment0 = attach0
hinge.Attachment1 = attach1
hinge.Parent = motor6D.Part0
hinge.LimitsEnabled = true
hinge.UpperAngle = 20
hinge.Restitution = 0
hinge.LowerAngle = -20
hinge.AngularResponsiveness = 0.5
elseif motor6D.Name == "LeftShoulder" then
ballSocket.UpperAngle = 30
ballSocket.TwistLowerAngle = -30
ballSocket.TwistUpperAngle = 30
elseif motor6D.Name == "RightShoulder" then
ballSocket.UpperAngle = 30
ballSocket.TwistLowerAngle = -30
ballSocket.TwistUpperAngle = 30
elseif motor6D.Name == "LeftElbow" then
ballSocket.LimitsEnabled = true
ballSocket.TwistLimitsEnabled = true
ballSocket.UpperAngle = 165
ballSocket.TwistLowerAngle = 0
ballSocket.TwistUpperAngle = 0
elseif motor6D.Name == "RightElbow" then
ballSocket.LimitsEnabled = true
ballSocket.TwistLimitsEnabled = true
ballSocket.UpperAngle = 165
ballSocket.TwistLowerAngle = 0
ballSocket.TwistUpperAngle = 0
else
ballSocket.LimitsEnabled = false
ballSocket.TwistLimitsEnabled = false
end
if motor6D.Name == "Neck" then
ballSocket.LimitsEnabled = true
ballSocket.TwistLimitsEnabled = true
ballSocket.UpperAngle = 0
ballSocket.TwistUpperAngle = 45
ballSocket.TwistLowerAngle = -45
end
if character.Humanoid.Health <= 0 then
motor6D:Destroy()
character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)
for i,v in pairs(character:GetDescendants()) do
if v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" then
local player = getNearestPlayer(character)
v:SetNetworkOwner(player)
end
end
character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)
character.PrimaryPart.Name = "Rooty"
spawn(function()
while true do
character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)
character.Humanoid:ChangeState(Enum.HumanoidStateType.Dead)
game:GetService("RunService").Heartbeat:Wait()
end
end)
end
elseif motor6D:IsA("Motor6D") then
local uc = Instance.new("UniversalConstraint")
local attach0 = Instance.new("Attachment")
local attach1 = Instance.new("Attachment")
local noCollision = Instance.new("NoCollisionConstraint")
uc.Attachment0 = attach0
uc.Attachment1 = attach1
uc.Parent = motor6D.Part0
attach0.CFrame = motor6D.C0
attach1.CFrame = motor6D.C1
attach0.Parent = motor6D.Part0
attach1.Parent = motor6D.Part1
attach0.Name = "Attachment0Ragdoll"
attach1.Name = "Attachment1Ragdoll"
noCollision.Name = motor6D.Part0.Name.."And"..motor6D.Part1.Name
noCollision.Part0 = motor6D.Part0
noCollision.Part1 = motor6D.Part1
noCollision.Parent = motor6D.Part0
end
end
end
function ragdoll(character)
for i, motor6D in pairs(character:GetDescendants()) do
if motor6D:IsA("Motor6D") then
if character.Humanoid.Health > 0 then
motor6D.Enabled = false
else
motor6D:Destroy()
end
end
end
end
function dropWeapons(character)
for i, v in pairs(character:GetDescendants()) do
if v:IsA("Tool") then
local oldCframe = v.Handle.CFrame
v.Parent = workspace
v.Handle.CFrame = oldCframe
end
end
end
function getNearestPlayer(npc)
local closest = nil
for _, player in pairs(game:GetService("Players"):GetPlayers()) do
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")
if humanoid.Health > 0 then
if not closest then
closest = player
else
if (npc.PrimaryPart.Position - char.PrimaryPart.Position).Magnitude < (closest.PrimaryPart.Position - npc.PrimaryPart.Position).Magnitude then
closest = player
end
end
end
end
return closest
end
function setup(character)
local humanoid = character:WaitForChild("Humanoid")
character.PrimaryPart.CanCollide = false
character.PrimaryPart.Massless = true
humanoid.BreakJointsOnDeath = false
humanoid.AutomaticScalingEnabled = false
setupJoints(character)
humanoid.Died:Connect(function()
character.Humanoid:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)
humanoid.MaxSlopeAngle = 359
ragdoll(character)
dropWeapons(character)
for i,v in pairs(character:GetDescendants()) do
if v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" then
local player = getNearestPlayer(character)
v:SetNetworkOwner(player)
end
end
character.PrimaryPart.Name = "Rooty"
while true do
humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)
humanoid:ChangeState(Enum.HumanoidStateType.Dead)
game:GetService("RunService").Heartbeat:Wait()
end
end)
end
As you can see, I have renamed the root part in order to prevent it from flying away, set every part’s network owner in the ragdoll to the nearest player to make it much smoother, renaming the root so that the Humanoid won’t make the ragdoll fly away, and I added a crude while loop to keep telling the ragdoll to not get up and to not use Platformstand.
The NPC still gets back up, sometimes.
In the video, I made a script to let the player fling the NPC and this help me to knock the NPC off their feet.
I have looked all over the devforum and internet and have not found a solid solution. Let me know if you have any ideas or I should post this in Engine Bugs due to the SetNetworkOwner() causing the humanoid issues most likely.
Thanks,
billybobpumpkin