How to make a clean NPC ragdoll?

howdy fello roblox devs! i have been trying for so long now but i just cant seem to make a clean, smooth, crispy ragdoll that satesfies you as you slap someone across the face in a roblox game. anyway, heres what i would LOVE for it to look like (i know it probably wont look this good and i dont think its roblox):


and heres what it looks like currently, the biggest problem at play currently is the lag from the npc as they start walking and when the ragdoll starts:

i really want to clarify that it looks fine if its on a player, its the NPC specifically that im trying to make look spicy. also its all server sided, as i tried client replication and it really does suck. for anyone reading this who would like more resources (videos, code, etc.) i would be more than happy to provide! i really appreciate you guys looking at this post and please do not hesitate to let me know if you have knowledge about this topic!

4 Likes

You’ve already posted this once, update that post… instead of creating a new one. Plus, if you want better assistance, provide code in your post.

Regarding Ragdolls, most people don’t like helping regarding ragdolls as they’re very tedious to deal with. With you having an issue with bots, I’d recommend adding a copy of your place so people can test different methods of ragdolling your bot.

1 Like

Ragdolls in roblox feel unatural because characters feel like they are weightless. You can try messing with custom physical properties and make more rigid joints.

1 Like

It usually is done by adding a slight impiuse in the direction your character is walking or moving in. If it’s walking then feet else if they are shot or slapped then at the point of contact.

For more realism you can make an animation and make the character move around a bit in the direction of the force.

wait(2)

for i, v in pairs(game:GetDescendants()) do
if v:IsA(“Model”) and v:FindFirstChildOfClass(“Humanoid”) then

	--> Make sure this script is located under the Character Model
	local Character: Model = v
	local Torso: BasePart = Character:WaitForChild("Torso")
	local Humanoid: Humanoid = Character:FindFirstChildOfClass("Humanoid")

	--> Necessary for Ragdolling to function properly
	Character.Humanoid.BreakJointsOnDeath = false
	Character.Humanoid.RequiresNeck = false

	--> Specific CFrame's made for the best looking Ragdoll
	local attachmentCFrames = {
		["Neck"] = {CFrame.new(0, 1, 0, 0, -1, 0, 1, 0, -0, 0, 0, 1), CFrame.new(0, -0.5, 0, 0, -1, 0, 1, 0, -0, 0, 0, 1)},
		["Left Shoulder"] = {CFrame.new(-1.3, 0.75, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1), CFrame.new(0.2, 0.75, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1)},
		["Right Shoulder"] = {CFrame.new(1.3, 0.75, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1), CFrame.new(-0.2, 0.75, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1)},
		["Left Hip"] = {CFrame.new(-0.5, -1, 0, 0, 1, -0, -1, 0, 0, 0, 0, 1), CFrame.new(0, 1, 0, 0, 1, -0, -1, 0, 0, 0, 0, 1)},
		["Right Hip"] = {CFrame.new(0.5, -1, 0, 0, 1, -0, -1, 0, 0, 0, 0, 1), CFrame.new(0, 1, 0, 0, 1, -0, -1, 0, 0, 0, 0, 1)},
	}

	local ragdollInstanceNames = {
		["RagdollAttachment"] = true,
		["RagdollConstraint"] = true,
		["ColliderPart"] = true,
	}

	--> Used to trigger Ragdoll
	local RagdollValue = Instance.new("BoolValue")
	RagdollValue.Name = "IsRagdoll"
	RagdollValue.Parent = Character
	-------------------------------------------------------------------------------------------------

	--> push :)
	local function push()
		local velRange = math.random() < 0.5 and {-35, -25} or {25, 35}
		local angularVelRange = math.random() < 0.5 and {-85, -30} or {30, 85}

		-- Torso:ApplyImpulse(Vector3.new(math.random(velRange[1], velRange[2]), 0, math.random(velRange[1], velRange[2])))
		Torso:ApplyAngularImpulse(Vector3.new(math.random(angularVelRange[1], angularVelRange[2]),math.random(angularVelRange[1], angularVelRange[2]),0)) --(Vector3.new(math.random(angularVelRange[1], angularVelRange[2]), math.random(angularVelRange[1], angularVelRange[2]), math.random(angularVelRange[1], angularVelRange[2])))
	end

	--> Allows for proper limb collisions
	local function createColliderPart(part: BasePart)
		if not part then return end
		local rp = Instance.new("Part")
		rp.Name = "ColliderPart"
		rp.Size = part.Size/1.7
		rp.Massless = true			
		rp.CFrame = part.CFrame
		rp.Transparency = 1

		local wc = Instance.new("WeldConstraint")
		wc.Part0 = rp
		wc.Part1 = part

		wc.Parent = rp
		rp.Parent = part
	end

	--converts motor 6d's with ballsocketconstraints
	local function replaceJoints()
		for _, motor: Motor6D in pairs(Character:GetDescendants()) do
			if motor:IsA("Motor6D") then
				if not attachmentCFrames[motor.Name] then return end
				motor.Enabled = false;
				local a0, a1 = Instance.new("Attachment"), Instance.new("Attachment")
				a0.CFrame = attachmentCFrames[motor.Name][1]
				a1.CFrame = attachmentCFrames[motor.Name][2]

				a0.Name = "RagdollAttachment"
				a1.Name = "RagdollAttachment"

				createColliderPart(motor.Part1)

				local b = Instance.new("BallSocketConstraint")
				b.Attachment0 = a0
				b.Attachment1 = a1
				b.Name = "RagdollConstraint"

				-- Set different constraint properties based on the joint
				if motor.Name == "Neck" then
					b.Radius = 0.1
					b.LimitsEnabled = true
					b.TwistLimitsEnabled = true
					b.UpperAngle = 45
					b.TwistLowerAngle = -70
					b.TwistUpperAngle = 70
				elseif motor.Name == "Left Shoulder" or motor.Name == "Right Shoulder" then
					b.Radius = 0.2
					b.LimitsEnabled = true
					b.TwistLimitsEnabled = true
					b.UpperAngle = 50
					b.TwistLowerAngle = -30
					b.TwistUpperAngle = 30
				elseif motor.Name == "Left Hip" or motor.Name == "Right Hip" then
					b.Radius = 0.3
					b.LimitsEnabled = true
					b.TwistLimitsEnabled = true
					b.UpperAngle = 25
					b.TwistLowerAngle = -30
					b.TwistUpperAngle = 30
				end

				b.MaxFrictionTorque = 0
				b.Restitution = 0

				a0.Parent = motor.Part0
				a1.Parent = motor.Part1
				b.Parent = motor.Parent
			end
		end
	end

	--> Destroys all Ragdoll made instances and re-enables the Motor6D's
	local function resetJoints()
		if Humanoid.Health < 1 then return end
		for _, instance in pairs(Character:GetDescendants()) do
			if ragdollInstanceNames[instance.Name] then
				instance:Destroy()
			end

			if instance:IsA("Motor6D") then
				instance.Enabled = true;
			end
		end
	end

	local function Ragdoll(value: boolean)
		if value then
			Humanoid:ChangeState(Enum.HumanoidStateType.Ragdoll)
			Humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
			replaceJoints()
			push()
		else 
			resetJoints()
			Humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
		end
	end

	-------------------------------------------------------------------------------------------------
	--> Connect the Events
	RagdollValue.Changed:Connect(Ragdoll)
	Humanoid.Died:Once(function()
		RagdollValue.Value = true
		push()
	end)
end

end
–[[
for i, v in pairs(workspace:GetChildren()) do
if v:IsA(“Model”) and v:FindFirstChildOfClass(“Humanoid”) then
wait(.25)
v:FindFirstChild(“IsRagdoll”).Value = true
end
end]]