Ragdoll Module doesn't unragdoll the player after the player makes a complete stop and somehow softlocks?

Hello there!

I’ve created a module script which handles ragdolls, specifically ones meant to replicate the ones games use like Item Asylum (Player gets ragdolled and gets unragdolled after making a complete stop).

There are a few issues with the module script shown with the video below however. Those being:

  1. The player doesn’t get unragdolled despite making a full stop.
  2. The player seems to be softlocked when trying to reset while being ragdolled.

Script

local RagdollModule = {}

function RagdollModule.Ragdoll(Character)
	local Humanoid = Character:WaitForChild("Humanoid")
	Humanoid:ChangeState(Enum.HumanoidStateType.Ragdoll)
	Humanoid.PlatformStand = true
	
	for i,v in pairs(Character:GetDescendants()) do
		if v:IsA("Motor6D") then
			local ballSocketConstraint = Instance.new("BallSocketConstraint")
			local attachment0 = Instance.new("Attachment")
			local attachment1 = Instance.new("Attachment")
			attachment0.Parent = v.Part0
			attachment1.Parent = v.Part1

			ballSocketConstraint.Parent = v.Parent
			ballSocketConstraint.Attachment0 = attachment0
			ballSocketConstraint.Attachment1 = attachment1

			attachment0.CFrame = v.C0
			attachment1.CFrame = v.C1

			ballSocketConstraint.MaxFrictionTorque = 200
			ballSocketConstraint.LimitsEnabled = true
			ballSocketConstraint.TwistLimitsEnabled = true

			v.Enabled = false
		end
	end
	
	if Humanoid.MoveDirection.Magnitude == 0 then
		task.wait(0.3)
		for i,v in pairs(Character:GetDescendants()) do
			if v:IsA("BallSocketConstraint") then
				v:Destroy()
			elseif v:IsA("Motor6D") then
				v.Enabled = true
			end
		end
		Humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
		Humanoid.PlatformStand = false
	end
end

return RagdollModule
1 Like

The above code is executed at the same time the player ragdolls. Consider using RunService.Stepped event instead, then for each player who ragdolls, add them to a table.

local RunService = game:GetService("RunService")

local UnragdollTimeDelay = 0.3
local MinimumVelocity = 0.05 -- The character won't be able to unragdoll if it's speed is almost, but not equal to 0.

local RagdollConnections = {} -- To deal with disconnecting events made by RagdollModule.Ragdoll()
local RagdolledCharacters = {}
local RagdollModule = {}

RunService.Stepped:Connect(function(_, DeltaTime)
	for Character, TimeLeft in pairs(RagdolledCharacters) do
		local MainPart = Character.PrimaryPart -- Assume the character has a PrimaryPart.
		
		-- Check the PrimaryPart's velocity instead. Humanoid.MoveDirection is related to
		-- the WALK direction of the character, not its velocity.
		if MainPart.Velocity.Magnitude > MinimumVelocity then
			RagdolledCharacters[Character] = UnragdollTimeDelay
			continue -- Skip the next lines of code
		end
		
		-- If the character is still enough, start the countdown.
		TimeLeft -= DeltaTime
		RagdolledCharacters[Character] = TimeLeft
		
		if TimeLeft > 0 then
			continue
		end
		
		-- It's good to unragdoll the character at this point.
		RagdollModule.Unragdoll(Character)
	end
end)

local function _unlistCharacter(Character)
	-- Disconnect the connections for Humanoid.Died and Model.Destroying made by RagdollSystem.Ragdoll()
	for _, connection in ipairs(RagdollConnections) do
		connection:Disconnect()
	end
	
	RagdollConnections[Character] = nil
	RagdolledCharacters[Character] = nil
end

local function _listCharacter(Character)
	-- Extra code just in case the character either: dies or is deleted.
	local Humanoid = Character:FindFirstChildWhichIsA("Humanoid")

	local function _removeFromList()
		_unlistCharacter(Character)
	end

	local Connections = {
		Character.Destroying:Once(_removeFromList),
		Humanoid.Died:Once(_removeFromList)
	}
	RagdolledCharacters[Character] = UnragdollTimeDelay -- Give this character a set time until it can be unragdolled.
	RagdollConnections[Character] = Connections
end

function RagdollModule.Ragdoll(Character : Model)
	-- Do not ragdoll if this character is already ragdolled.
	if RagdolledCharacters[Character] ~= nil then return end
	
	local Humanoid = Character:FindFirstChildWhichIsA("Humanoid")
	Humanoid:ChangeState(Enum.HumanoidStateType.Ragdoll)
	Humanoid.PlatformStand = true

	for i,v in pairs(Character:GetDescendants()) do
		if v:IsA("Motor6D") then
			local ballSocketConstraint = Instance.new("BallSocketConstraint")
			local attachment0 = Instance.new("Attachment")
			local attachment1 = Instance.new("Attachment")
			attachment0.Parent = v.Part0
			attachment1.Parent = v.Part1

			ballSocketConstraint.Parent = v.Parent
			ballSocketConstraint.Attachment0 = attachment0
			ballSocketConstraint.Attachment1 = attachment1

			attachment0.CFrame = v.C0
			attachment1.CFrame = v.C1

			ballSocketConstraint.MaxFrictionTorque = 200
			ballSocketConstraint.LimitsEnabled = true
			ballSocketConstraint.TwistLimitsEnabled = true

			v.Enabled = false
		end
	end
	
	_listCharacter(Character)
end

function RagdollModule.Unragdoll(Character : Model)
	-- Do not unragdoll if the character isn't even ragdolled.
	if RagdolledCharacters[Character] == nil then return end
	
	local Humanoid = Character:FindFirstChildWhichIsA("Humanoid")
	
	for i,v in pairs(Character:GetDescendants()) do
		if v:IsA("BallSocketConstraint") then
			v:Destroy()
		elseif v:IsA("Motor6D") then
			v.Enabled = true
		end
	end
	
	Humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
	Humanoid.PlatformStand = false
	
	_unlistCharacter(Character)
end

return RagdollModule
1 Like

I think it works correctly! Thanks alot man!

2 Likes

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