I have been working on a character throwing system, and there is a potential for a player to throw many characters at once, so I’ve decided to only render the character on the client side to conserve resources. The client-sided character being thrown is welded to its own server-side root part. This part has the AssemblyLinearVelocity property changed to create the throw.
The parts in the client-sided character model are held together with BallSocketConstraints to create a ragdoll effect, with the exception of the head, upper torso, and lower torso, which are held by Motor6Ds. When the velocity is applied to the server part, the parts held by Motor6Ds actually hold together and are thrown. The limbs, however, are left behind and the BallSocketConstraint ceases to function. There is some sort of weird stretching effect.
Here are two videos of the issue with different camera angles:
I’ve attached a few snippets of code below:
Client-sided ragdoll function:
local function ragdoll(friendModel)
for i, v in pairs(friendModel:GetDescendants()) do
if v:IsA("Motor6D") and v.Name ~= "Neck" and v.Name ~= "Waist" and v.Name ~= "Root" then
local Constraint = Instance.new("BallSocketConstraint")
Constraint.Name = v.Name
Constraint.Radius = 1
Constraint.LimitsEnabled = true
Constraint.TwistLimitsEnabled = true
Constraint.TwistLowerAngle = -45
Constraint.TwistUpperAngle = 90
Constraint.MaxFrictionTorque = 3
local attachment1 = v.Part1:FindFirstChild(v.Name.."Attachment") or v.Part1:FindFirstChild(v.Name.."RigAttachment")
local attachment0 = v.Part0:FindFirstChild(v.Name.."Attachment") or v.Part0:FindFirstChild(v.Name.."RigAttachment")
if attachment1 and attachment0 then
Constraint.Attachment1 = attachment1
Constraint.Attachment0 = attachment0
Constraint.Parent = v.Parent
v.Enabled = false
end
elseif v:IsA("BasePart") then
v.Massless = true
v.CollisionGroup = "Friends"
end
end
end
Server-sided throw script:
HRP.Anchored = true
HRP.Orientation = orientation
local animTrack = playAnim(plr, "rbxassetid://90109218766018")
animTrack:GetMarkerReachedSignal("StartThrow"):Wait()
local animSpeed = BV/startBV
if animSpeed > maxAnimSpeed then
animSpeed = maxAnimSpeed
end
animTrack:AdjustSpeed(animSpeed)
local friendFolder = rigFolders:WaitForChild(plr.Name)
local friendModels = friendFolder:GetChildren()
for i, hitbox in pairs(friendModels) do -- Each hitbox is a server-sided character root part
hitbox.Weld.Enabled = false
hitbox.AssemblyLinearVelocity = velocity
if i == #friendModels then
remotes.viewFriend:FireClient(plr, true, hitbox)
end
end