How do I make a Skinned Mesh into a ragdoll with a script?

  1. What do you want to achieve? I want to turn a Skinned Mesh of a Half-Life 2 character into a ragdoll

  2. What is the issue? None of the bones move.
    https://gyazo.com/cf958ecfc5cdd86e290f6fa96de93b21

  3. What solutions have you tried so far? Tried making the ball socket joints attachments 0 and 1 to the bone and it’s parent and if it has no parent attachment 1 is attachment 0.

This is the script I created.

for i,v in pairs(script.Parent:WaitForChild("RootPart"):GetDescendants()) do
	if v:IsA("Bone") then
		local attachment = Instance.new("BallSocketConstraint", v)
		attachment.Name = "ragdolljoint"
		attachment.Attachment0 = v
		if v.Parent:IsA("Bone") then
			attachment.Attachment1 = v.Parent
		else
			attachment.Attachment1 = v
		end
	end
end

It makes no errors and the bones don’t rotate or move.

edit: this is way later and i LOVE IT https://gyazo.com/44f9c7a2826dcffa597d94cf09c8c77f

8 Likes

I’m working on a solution that works with parts.

1 Like

nevermind it literally shakes but yeah it’s too funny so this is solved.

Hey im not sure if you figured out how to make it work like a normal ragdoll or not. But i wanted to also make a skinned-mesh ragdoll so i started off with what you made here, and i finally figured out how to make it(kinda). But there isnt much on how to make it so im gonna post the way i did it here.

–The Result: https://gyazo.com/5406bb34a07a2df69a61ffc8d534fd96
–Better Video: Roblox Skinned Mesh Ragdoll - YouTube

–Note: this method has a flaw that the meshparts and HumanoidRootPart don’t follow the ragdoll and i cant figure out a way to make it do so without the ragdoll breaking, But i hope someone here figures it out and shares it.

1, chop the mesh into separate limbs(Doesnt Have To Be R-15) And then using motor6d’s to connect them like a normal rig.
–The next part i did in a script–

2, In the script i used for i,v in pairs() to find all the mesh limbs that have a bone (for e.g: Mesh: “Head”, Bone: “mixamorig:Head”) and make a part with the same size, orientation and position as the Mesh and set its transparency to 1. And then set the CanCollide to false for the meshPart we just created a part for.

3, I make an attachment inside the part i just made and move its WorldCFrame to the WorldCFrame of the Bone its linked to. Then i spawn a function, which uses Heartbeat to move the Bone.WorldCFrame to the WorldCFrame of the attachment.

4, Then i use another for i,v in pairs() to find all the motor6d’s that both their “Part0” and “Part1” have a bone (like step 2), then i make a attachment and set the parent to the part we made in step1 which Corresponds to the meshPart inside “Part0”. And do the same for “Part1.”
(For e.g: If Part0 is “Head” i make the parent of the attachment to the part i made for “Head” in step1)

5, Move the first Attachemnt to motor6d.C0 and second Attachment to motor6d.C1

6, Create a BallSocketConstraint with the parent being the same parent as the first attachment in step4, And set its Attachment0 and Attachment1 to the attachments we made in step4.

7, Now just unanchor all the parts we made in step1 and it should ragdoll!

–Sorry if it was confusing but its my first time posting a post here, since i wanted to make skinned mesh ragdolls but i couldn’t find anything that actually works.

–My Script, It has some extra things so i can customize it more but all you need is listed in the steps above.

--Made By Callme_jj

local char = script.Parent
local CharBones = char:WaitForChild("HumanoidRootPart"):GetDescendants()
local RagDollPartsFolder = Instance.new("Folder",char) --Create Folder To Parent All GhostParts.
RagDollPartsFolder.Name = "RagDollPartsFolder"


local RunService = game:GetService("RunService")--HeartBeat To Move Bones To Attachments Location, And Move RootPart.
local RATE_PER_SECOND = 500 --How Many Times Per Second To Move Bones.

local BoneDict = { --Dictionary To Refrence Bones From Body MeshPart Name.

	Head = "mixamorig:Head",
	LeftFoot = "mixamorig:LeftFoot",
	LeftHand = "mixamorig:LeftHand",
	LeftLowerArm = "mixamorig:LeftForeArm",
	UpperTorso = "mixamorig:Spine",
	LeftLowerLeg = "mixamorig:LeftLeg",
	LeftUpperArm = "mixamorig:LeftArm",
	LeftUpperLeg = "mixamorig:LeftUpLeg",
	LowerTorso = "mixamorig:Hips",
	RightFoot = "mixamorig:RightFoot",
	RightHand = "mixamorig:RightHand",
	RightLowerArm = "mixamorig:RightForeArm",
	RightLowerLeg = "mixamorig:RightLeg",
	RightUpperArm = "mixamorig:RightArm",
	RightUpperLeg = "mixamorig:RightUpLeg",
}


local BoneLimits = { --Dictionary To Refrence Bones Ball Socket Limits.
	
	Head = {UpperAngle = 45, TwistLowerAngle = -22.5, TwistUpperAngle = 22.5}, --Main Parts
	UpperTorso = {UpperAngle = 45, TwistLowerAngle = -35, TwistUpperAngle = 120},
	LowerTorso = {UpperAngle = 45, TwistLowerAngle = -20, TwistUpperAngle = 20},
	
	LeftUpperLeg = {UpperAngle = 35, TwistLowerAngle = 0, TwistUpperAngle = 180}, --Left Leg
	LeftLowerLeg = {UpperAngle = 0, TwistLowerAngle = 0, TwistUpperAngle = 0},
	LeftFoot = {UpperAngle = 1, TwistLowerAngle = -35, TwistUpperAngle = 35},
	
	LeftUpperArm = {UpperAngle = 45, TwistLowerAngle = 0, TwistUpperAngle = 0}, --Left Arm
	LeftLowerArm = {UpperAngle = 45, TwistLowerAngle = -20, TwistUpperAngle = 20},
	LeftHand = {UpperAngle = 35, TwistLowerAngle = -180, TwistUpperAngle = 180},
	
	RightUpperLeg = {UpperAngle = 35, TwistLowerAngle = 0, TwistUpperAngle = 180}, --Right Leg
	RightLowerLeg = {UpperAngle = 0, TwistLowerAngle = 0, TwistUpperAngle = 0},
	RightFoot = {UpperAngle = 25, TwistLowerAngle = -35, TwistUpperAngle = 35},
	
	RightUpperArm = {UpperAngle = 45, TwistLowerAngle = 0, TwistUpperAngle = 0}, --Right Arm
	RightLowerArm = {UpperAngle = 45, TwistLowerAngle = -20, TwistUpperAngle = 20},
	RightHand = {UpperAngle = 1, TwistLowerAngle = -35, TwistUpperAngle = 35},
	
}




--Make Attachments For Each MeshPart And Position It Where The Bone Is.
for index,Child in pairs(char:GetChildren()) do
	if Child:IsA("MeshPart") and BoneDict[Child.Name] then --Check If Child Is A Mesh And If A Bone Exists In Bone Dictionary.
		local ChildLinkedBone
		
		for i, Bone in pairs(CharBones) do --Get The Bone Object From The Character.
			if Bone.Name == BoneDict[Child.Name] then
				ChildLinkedBone = Bone
			end
		end
		
		local GhostPart = Instance.new("Part", RagDollPartsFolder) --Create, Size/Position && Name GhostPart.
		GhostPart.Size = Child.Size
		GhostPart.CFrame = Child.CFrame
		GhostPart.Name = (Child.Name.."-Ghost")
		GhostPart.Anchored = true
		GhostPart.Transparency = 1
		GhostPart.CanCollide = true
		
		local BoneAtt = Instance.new("Attachment", GhostPart) --Create And Position Bone Attachment.
		BoneAtt.WorldCFrame = ChildLinkedBone.WorldCFrame
		BoneAtt.Name = (GhostPart.Name.."-BoneAtt")
		
		
		Child.CanCollide = false --Turn Off Main Mesh CanCollide.
		
		spawn(function() --Heartbeat to move the bone's CFrame to the attachments CFrame.
			RunService.Heartbeat:Connect(function(step)
				ChildLinkedBone.WorldCFrame = BoneAtt.WorldCFrame
			end)
		end)
		
		
	end
end


--Make BallSocket From Motor6d.
for index, Child in pairs(char:GetDescendants()) do 
	if Child:IsA("Motor6D") and BoneDict[Child.Part0.Name] and BoneDict[Child.Part1.Name] then --Check If Child Is A Motor6D And If Both Part0 and Part1 Have Ghost Bones.
		
		local GhostPart0 = RagDollPartsFolder:WaitForChild(Child.Part0.Name.."-Ghost") --Get Ghost parts.
		local GhostPart1 = RagDollPartsFolder:WaitForChild(Child.Part1.Name.."-Ghost")
		
		local Att0 = Instance.new("Attachment",GhostPart0) --Create Attachements For BallSocket Constraint.
		local Att1 = Instance.new("Attachment",GhostPart1)
		
		Att0.Name = GhostPart0.Name.."-BallAtt" --Name Attachments For Debugging Purposes.
		Att1.Name = GhostPart1.Name.."-BallAtt"
		
		Att0.CFrame = Child.C0 --Set The Attachments CFrame To The Joints CFrame.
		Att1.CFrame = Child.C1
		
		local BallConstraint = Instance.new("BallSocketConstraint", GhostPart0) --Create BallSocket Constraint And Set Its Attachments.
		BallConstraint.Attachment0, BallConstraint.Attachment1 = Att0, Att1
		
		BallConstraint.TwistLimitsEnabled = true --Set BallSocket Limits.
		BallConstraint.LimitsEnabled = true
		BallConstraint.UpperAngle = BoneLimits[Child.Part0.Name].UpperAngle
		BallConstraint.TwistLowerAngle = BoneLimits[Child.Part0.Name].TwistLowerAngle
		BallConstraint.TwistUpperAngle = BoneLimits[Child.Part0.Name].TwistUpperAngle
		
		print("BallSocket Constraint Created For "..GhostPart0.Name.." And "..GhostPart1.Name..".")
	end
end

--UnAnchor All GhostParts.
for i,v in pairs(RagDollPartsFolder:GetChildren()) do
	v.Anchored = false
end

char:FindFirstChild("HumanoidRootPart").CanCollide = false

```lua
26 Likes

Thank you! I needed this in November but I don’t require it for now, but it could be useful in future projects. You should make a post about this to teach others about your method, as this seems interesting.

2 Likes

This is really helpful, but how about the custom skinned meshes that aren’t R6, R15, or Rthro?

1 Like

The skinned mesh doesn’t have to be an R15/R6 or Rthro rig. All you have to do is include the bone along with the Ball Socket Limits in the 2 dictionaries.

Although my original post would probs still work, I wouldn’t really recommend using it, even for R15 rigs. The reason is that I had originally written that method before learning about “S15” rigs, where the mesh is already chopped and the bones can be moved automatically when the mesh part with the same name as the bone, moves.

So the new method, if I were to do this again, would be creating a rig the S15 way (Even though it was meant for skinned rigs that resemble the r15 rig to use normal roblox animations, they still also work with other rig types, if you name everything correctly.) Then just use a normal ragdoll script that just converts motor6d’s to ball and socket constraints.

This way, you don’t have to re-position the bones using runservice, which isn’t that performant.

But if you are still going to use the original method, use :GetPropertyChangedSignal to detect when the BoneAtt’s CFrame changes to update the bones, instead of updating every single bone, every heartbeat…

1 Like

What about for a specific bone?

I’m not really sure what you mean. But as I said in the reply, the rig type doesn’t matter. For e.g, here is a ragdoll hair rig and a cloth rig I made using what I described in the reply.

This is what the hair rig looks like, extremely different to an r15 rig and yet it still works.

And this is what I mean when I say that you dont have to move the bones when using a rig made the S15 way, since Roblox does it automatically.

3 Likes

Thanks for all the tips! I was really struggling on how to make realistic wingflex on airplane wings that move by any bump, or by landing intensity also by adding spring constraints.

I am trying to do this for a cloth simulation for a game. but the problem I’m having is I don’t know how to cut them mesh up into parts and still have it mesh deform. I did it but when I added the motor6d to it and ran the game the mesh parts just broke into pieces and didn’t mesh deform


One script, one BoolValue

2 Likes

Hey, I know you mentioned that the HumanoidRootPart doesn’t move, but I don’t know whether that is related to my issue. The back does not move with the rest of the body.

This is the result I get:

Here is my file explorer:

Any help is greatly appreciated :grinning:

1 Like

Bumping this:
Currently having some grief rigging tank treads so they move with suspension as they make contact with the ground. Not entirely sure as to how to import it / structure the mesh in blender. Importing was done through the custom avatar importer and file structure is pretty much identical to the post above this.


Any help is appreciated

2 Likes

This deserves its own thread, awesome work!

I forgot this thread existed, 3 years fly by fast. I eventually did use the script for something, not the Metro Police, rather a Left 4 Dead 2 Hunter ragdoll though.