How can i improve my ragdolling code?

Hello, I’ve been making a fighting game with friends, and so far it’s been going pretty well, except for one problem:

The ragdoll system is buggy

Some bugs that with it:
-Ragdolled user is flung after getting up
-Ragdolled user can “float” (ragdolled but still has normal control)
-Ragdolled user unragdolls but stays on the floor unable to move for a while longer

Please keep in mind that local solutions might not be the best, as NPCs can also be ragdolled.

Here is my code:

local function ragdoll(char:Model,humanoid:Humanoid)
	--humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, false)
	humanoid:ChangeState(Enum.HumanoidStateType.Ragdoll)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)

	humanoid.PlatformStand = true

	for i,joint in pairs(char:GetDescendants()) do
		if typeof(joint) == "Instance" and joint:IsA("Motor6D") then
			local attach1 = Instance.new("Attachment")
			attach1.CFrame = joint.C0
			attach1.Parent = joint.Part0

			local attach2 = Instance.new("Attachment")
			attach2.CFrame = joint.C1
			attach2.Parent = joint.Part1

			local socket = Instance.new("BallSocketConstraint")
			socket.Attachment0 = attach1
			socket.Attachment1 = attach2
			socket.LimitsEnabled = true
			socket.TwistLimitsEnabled = true
			socket.Parent = joint.Parent

			joint.Enabled = false
		end
	end
end

local function unragdoll(char:Model,humanoid:Humanoid)
	for i,thing in pairs(char:GetDescendants()) do
		if typeof(thing) == "Instance" then
			if thing:IsA("BallSocketConstraint") then
				thing:Destroy()
			elseif thing:IsA("Motor6D") then
				thing.Enabled = true
			end
		end
	end
	--humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, true)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, true)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
	
	local bodyvel = Instance.new("BodyVelocity")
	bodyvel.MaxForce = Vector3.new(0,1,0)*300000
	bodyvel.P = 25000
	bodyvel.Velocity = Vector3.new(0,0,0)
	bodyvel.Parent = char.HumanoidRootPart
	
	game.Debris:AddItem(bodyvel,0.25)
	
	--preventFling(char)
	humanoid.PlatformStand = false

	humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
end

Note: The BodyVelocity made in the Unragdoll function was a test solution to try and fix the flinging bug, didn’t really fix it that well

Thanks.

for point 2. i would suggest instead of making the players state become “ragdoll”, that it be changed to “PlatformStanding”, as this means it will permanently be stuck in ragdoll and wont try to readjust back into the gettingup state by itself until changed.

for the other two, this is mainly dependant on the way Humanoids actually get up. if upside down or in a weird orientation, like point 3, they may get ragdolled again when trying to get up which makes the ragdoll seem longer than set to be. for point 1, sometimes when this get up state change fails, the force that would have been neutralised when making the character rapidly move into the standing animation is left untouched which means that it sends the character, while ragdolled, flying. for both these points, i would suggest teleporting the character into its right position, stood up, before letting the humanoid get up, so that once the humanoid tries standing up it minimalizes any stupid failures!

I changed it a bit based on what you said, would this be better?

local function ragdoll(char:Model,humanoid:Humanoid)
	--humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, false)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)

	humanoid.PlatformStand = true

	for i,joint in pairs(char:GetDescendants()) do
		if typeof(joint) == "Instance" and joint:IsA("Motor6D") then
			local attach1 = Instance.new("Attachment")
			attach1.CFrame = joint.C0
			attach1.Parent = joint.Part0

			local attach2 = Instance.new("Attachment")
			attach2.CFrame = joint.C1
			attach2.Parent = joint.Part1

			local socket = Instance.new("BallSocketConstraint")
			socket.Attachment0 = attach1
			socket.Attachment1 = attach2
			socket.LimitsEnabled = true
			socket.TwistLimitsEnabled = true
			socket.Parent = joint.Parent

			joint.Enabled = false
		end
	end
end

local function unragdoll(char:Model,humanoid:Humanoid)
	for i,thing in pairs(char:GetDescendants()) do
		if typeof(thing) == "Instance" then
			if thing:IsA("BallSocketConstraint") then
				thing:Destroy()
			elseif thing:IsA("Motor6D") then
				thing.Enabled = true
			end
		end
	end
	--humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, true)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, true)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
	humanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
	
	--[[local bodyvel = Instance.new("BodyVelocity")
	bodyvel.MaxForce = Vector3.new(0,1,0)*300000
	bodyvel.P = 25000
	bodyvel.Velocity = Vector3.new(0,0,0)
	bodyvel.Parent = char.HumanoidRootPart
	
	game.Debris:AddItem(bodyvel,0.25)--]]
	
	--preventFling(char)
	humanoid.PlatformStand = false

	humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
	
	char.HumanoidRootPart.CFrame += Vector3.new(0,1.5,0)
end

this line isnt very necessary as once the Humanoid is put into the PlatformStand state, it will be forced into ragdoll and wont try to change its state back until you change this variable back.

same thing down here, you can replace these three lines with Humanoid.PlatformStand = false and it should produce the same effect

however as i said you will need to actually teleport the player back standing up manually so the humanoid wont freak out on occasions when it tries to do it itself

This should be good then, right?

local collisionChangeBlacklist = {"Handle","Torso","HumanoidRootPart","Head"}

local function ragdoll(char:Model,humanoid:Humanoid)
	humanoid.PlatformStand = true

	for i,thing in pairs(char:GetDescendants()) do
		if typeof(thing) == "Instance" then
			if thing:IsA("Motor6D") then
				local attach1 = Instance.new("Attachment")
				attach1.CFrame = thing.C0
				attach1.Parent = thing.Part0

				local attach2 = Instance.new("Attachment")
				attach2.CFrame = thing.C1
				attach2.Parent = thing.Part1

				local socket = Instance.new("BallSocketConstraint")
				socket.Attachment0 = attach1
				socket.Attachment1 = attach2
				socket.LimitsEnabled = true
				socket.TwistLimitsEnabled = true
				socket.Parent = thing.Parent

				thing.Enabled = false
			elseif thing:IsA("BasePart") and not table.find(collisionChangeBlacklist,thing.Name) then
				thing.CanCollide = true
			end
		end
	end
end

local function unragdoll(char:Model,humanoid:Humanoid)
	for i,thing in pairs(char:GetDescendants()) do
		if typeof(thing) == "Instance" then
			if thing:IsA("BallSocketConstraint") then
				thing:Destroy()
			elseif thing:IsA("Motor6D") then
				thing.Enabled = true
			elseif thing:IsA("BasePart") and not table.find(collisionChangeBlacklist,thing.Name) then
				thing.CanCollide = false
			end
		end
	end

	char.HumanoidRootPart.CFrame = (char.HumanoidRootPart.CFrame + Vector3.new(0,2,0)) * CFrame.Angles(math.rad(-90),0,0)
	humanoid.PlatformStand = false

	--humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
end

sir yes sir, repeating this for character count but when/if you implement the teleport into standing position function, remember to make it run before you set the PlatformStand variable back to false in the unragdoll function or else the Humanoid will ignore the teleport and try to stand up again as soon as you change the variable

The teleport-into-standing-position function is already implemented, if you look in the unragdoll function, right before the end, you’ll see the teleport function which is done right before PlatformStand is set to false.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.