You can write your topic however you want, but you need to answer these questions:
-
What do you want to achieve? Keep it simple and clear!
When a ragdoll collapses to the ground, i want it to emit effects, but this happpens -
What is the issue? Include screenshots / videos if possible!
-
What solutions have you tried so far? Did you look for solutions on the Creator Hub?
I looked up a solution, couldn’t find any that matches the same topic
Here’s the script, the Problem
local IMPACT_SPEED_THRESHOLD = 40
local lastImpactTime = 0
local IMPACT_COOLDOWN = 1
local HumanoidRootPart = characterRagdoll:FindFirstChild("HumanoidRootPart")
HumanoidRootPart.Touched:Connect(function(hit)
if hit:IsDescendantOf(characterRagdoll) then return end
local speed = HumanoidRootPart.AssemblyLinearVelocity.Magnitude
local now = os.clock()
if speed >= IMPACT_SPEED_THRESHOLD and (now - lastImpactTime) >= IMPACT_COOLDOWN then
lastImpactTime = now
Effect:createDebris(characterRagdoll,5,1,HumanoidRootPart.CFrame)
if #RagdollSoundTable > 0 then
local randomSound = RagdollSoundTable[math.random(1, #RagdollSoundTable)]:Clone()
randomSound.Parent = HumanoidRootPart
randomSound:Play()
game.Debris:AddItem(randomSound, randomSound.TimeLength + 0.1)
end
end
end)
Here’s the Particle Emitter script that is being used
function Effect:createDebris(Model : Model,amount,Time,cFrame)
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {Model}
local Raycast = workspace:Raycast(Model.PrimaryPart.Position, Vector3.new(0,-100,0),params)
print(Raycast.Instance)
task.spawn(function()
for i = 1, amount do
task.wait(Time)
local debris = Instance.new("Part")
local Size = Random.new():NextNumber(0.25, 1)
debris.Material = Raycast.Instance.Material
debris.Color = Raycast.Instance.Color
debris.Massless = true
debris.Size = Vector3.new(Size,Size,Size)
debris.Parent = workspace.InGame.FX
debris.CFrame = cFrame
debris.RotVelocity = Vector3.new(math.random(-50,50), math.random(-25,25), math.random(-25,25))
local BodyVel = Instance.new("BodyVelocity")
BodyVel.Velocity = Vector3.new(math.random(-50,50), math.random(7,30), math.random(-50,50))
BodyVel.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
BodyVel.Parent = debris
game.Debris:AddItem(BodyVel, 0.1)
game.Debris:AddItem(debris, 5)
local Trail = script.debrisTrail:Clone()
local att0 = Instance.new("Attachment")
local att1 = Instance.new("Attachment")
att0.CFrame = CFrame.new(0,0.2,0)
att1.CFrame = CFrame.new(0,-0.2,0)
att0.Parent = debris
att1.Parent = debris
Trail.Parent = debris
Trail.Attachment0 = att0
Trail.Attachment1 = att1
task.delay(4,function()
local tween = TweenService:Create(debris, TweenInfo.new(1), {Size = Vector3.zero})
tween:Play()
end)
end
end)
end
And here’s the whole ragdoll Script
--[[
____ _ _ _ __ __ _ _
| _ \ __ _ __ _ __| | ___ | | | | \/ | ___ __| |_ _| | ___
| |_) / _` |/ _` |/ _` |/ _ \| | | | |\/| |/ _ \ / _` | | | | |/ _ \
| _ < (_| | (_| | (_| | (_) | | | | | | | (_) | (_| | |_| | | __/
|_| \_\__,_|\__, |\__,_|\___/|_|_| |_| |_|\___/ \__,_|\__,_|_|\___|
|___/
by @igd3v, v1.2.1
CHANGES
- v1.1:
> Now you can ragdoll characters without destroying them.
> Fixed AutoDestroy cleanup to make it actually cleanup
> Fixed a typo in cloneModel
> Added Types.RagdollType
> Added Types.RagdolCache
> Added the "Ragdoll:setRagdollType()" method
> Added "_ragdollCache" table to save joints and reuse them.
- v1.1.1:
> Fixed error that caused :doRagdoll to not work.
> Fixed physics collisions for rig compatibility.
> Fixed Network Owner Management.
> Fixed _ragdollCache management.
- v1.1.2:
> Fixed ragdolls with DeathBody Type.
> Fixed the constraint joining method.
> Fixed and restructured code in :doRagdoll().
> Made ragdoll collision hitboxes a bit smaller
> Added debug mode
- v1.2:
> Added the TwistAngleRange variable.
> Now you can set all your values in one go.
> WARNING; PLEASE UPDATE YOUR .new() CALLS TO THE NEW FORMAT: .new(Character:Model, DataTable:RagdollProperties)
- v1.2.1:
> Now you can call Ragdoll:destroy() to destroy the ragdoll object.
> Now you can access other ragdoll from the module by using getRagdoll()
> Now you can check if the ragdoll is currently ragdolling with ragdoll:isRagdolling()
> You can also now define a custom ID for the ragdoll to be stored in. (i.e. ragdoll with id "hello" will be stored as ragdolls["hello"])
]]
local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local HTTPService = game:GetService("HttpService")
local Sounds = ReplicatedStorage:FindFirstChild("Sounds")
local Storage = ReplicatedStorage:FindFirstChild("Storage")
local FX = ReplicatedStorage:FindFirstChild("FX")
local Modules = Storage:FindFirstChild("Modules")
local Combat = FX:FindFirstChild("Combat")
local RagdollSounds = Sounds:FindFirstChild("Ragdoll")
local RagdollSoundTable = RagdollSounds:GetChildren()
local Util = require(Modules.Utilities)
local Effect = require(Modules.Effect)
local ConcreteTable = {
Enum.Material.Concrete,
Enum.Material.Plastic,
Enum.Material.SmoothPlastic,
Enum.Material.Brick,
Enum.Material.Plaster
}
local Types = require(script.Types)
local ragdoll = {} :: Types.Ragdoll
ragdoll.__index = ragdoll
local ragdolls = {} :: {Types.Ragdoll}
local function cloneModel(model:Model)
local wasArchivable = false
if not model.Archivable then
model.Archivable = true
end
local clone = model:Clone()
return clone
end
local function join(joint: Motor6D?, twistAngleRange: number, destroyOld: boolean):(BallSocketConstraint, Motor6D?)
local socketName = joint.Name:gsub("%s+", "") .. "Socket"
local existingSocket = joint.Parent:FindFirstChild(socketName)
if existingSocket then
return existingSocket
end
local socket = Instance.new("BallSocketConstraint")
socket.Name = socketName
local a1 = joint.Part0:FindFirstChild(socketName .. "_A0")
local a2 = joint.Part1:FindFirstChild(socketName .. "_A1")
if not a1 then
a1 = Instance.new("Attachment")
a1.Name = socketName .. "_A0"
a1.CFrame = joint.C0
a1.Parent = joint.Part0
end
if not a2 then
a2 = Instance.new("Attachment")
a2.Name = socketName .. "_A1"
a2.CFrame = joint.C1
a2.Parent = joint.Part1
end
socket.Parent = joint.Parent
socket.Attachment0 = a1
socket.Attachment1 = a2
socket.LimitsEnabled = true
socket.TwistLimitsEnabled = true
socket.TwistLowerAngle = -(twistAngleRange / 2)
socket.TwistUpperAngle = twistAngleRange / 2
if destroyOld then
joint.Part0 = nil
joint.Part1 = nil
joint.Enabled = false
joint:Destroy()
end
return socket
end
local function initRagdollFolder()
if workspace:FindFirstChild("__ragdoll") then return workspace:FindFirstChild("__ragdoll") end
local folder = Instance.new("Folder")
folder.Name = "__ragdoll"
folder.Parent = workspace
return folder
end
local function initCollisionGroup()
if not game.PhysicsService:IsCollisionGroupRegistered("__ragdollColl") then
game.PhysicsService:RegisterCollisionGroup("__ragdollColl")
game.PhysicsService:CollisionGroupSetCollidable("Default", "__ragdollColl", true)
game.PhysicsService:CollisionGroupSetCollidable("__ragdollColl", "__ragdollColl", false)
end
end
local function getRagdollModel(ragType:Types.RagdollType, src:Model?):Model?
if not src then return end
if ragType == "DeathBody" then
return cloneModel(src)
elseif ragType == "Toggle" then
return src
end
end
local function createOrGetCollisionBox(child:BasePart):(Part, Weld)
if child:FindFirstChild("_collision") and child:FindFirstChild("_collision"):FindFirstChildOfClass("Weld") then
return child:FindFirstChild("_collision"), child:FindFirstChild("_collision"):FindFirstChildOfClass("Weld")
end
local collisionBox = Instance.new("Part")
collisionBox.Size = child.Size * 0.75
collisionBox.CanCollide = true
collisionBox.Transparency = 1
collisionBox.CanTouch = false
collisionBox.CanQuery = false
collisionBox.CollisionGroup = "__ragdollColl"
local weld = Instance.new("Weld")
weld.Part0 = child
weld.Part1 = collisionBox
collisionBox.Name = `_collision`
collisionBox.Parent = child
weld.Parent = collisionBox
return collisionBox, weld
end
local function tryStoreRagdoll(obj:Types.Ragdoll, id:string)
if ragdolls[id] then
error("Ragdoll already exists at key "..id)
end
ragdolls[id] = obj
end
-- Creates a new ragdoll handler.
function ragdoll.new(Character:Model, DataTable:Types.RagdollProperties)
assert(Character, "Ragdoll Character is required.")
assert(typeof(DataTable) == "table", "The .new() method has been updated and its old use has been deprecated. Please use the new format: new(Character:Model, DataTable:RagdollProperties)")
local self = (setmetatable({}, ragdoll)::unknown)::Types.Ragdoll
self.Character = Character
self.RemovalTime = DataTable.RemovalTime or 5
self.CollisionsEnabled = DataTable.CollisionsEnabled or true
self.DoFadeOnRemovalReached = DataTable.DoFadeOnRemovalReached or true
self.FadeTime = DataTable.FadeTime or 10
self.Friction = DataTable.Friction or 0.25
self.Elasticity = DataTable.Elasticity or 0.7
self.Density = DataTable.Density or 0.5
self.Player = DataTable.Player or nil
self.AutoDestroy = DataTable.AutoDestroy or true
self.RagdollType = DataTable.RagdollType or "DeathBody"
self.DebugMode = DataTable.DebugMode or false
self.TwistAngleRange = DataTable.TwistAngleRange or 45
self._ragdollCache = {}
self._ragdollGUID = DataTable.ID or HTTPService:GenerateGUID()
self._ragdolling = false
tryStoreRagdoll(self, self._ragdollGUID)
if Character then
local Humanoid = Character:WaitForChild("Humanoid", 5)
if Humanoid then
Humanoid.RequiresNeck = false
Humanoid.BreakJointsOnDeath = false
end
end
return self
end
function ragdoll:destroy()
if ragdolls[self._ragdollGUID] then
ragdolls[self._ragdollGUID] = nil
end
table.clear(self)
setmetatable(self, nil)
end
function ragdoll:debug(msg)
if self.DebugMode then
print(`[DEBUG][RagdollModule]: {tostring(msg)}`)
end
end
-- Sets the Ragdoll type
function ragdoll:setRagdollType(ragdollType:Types.RagdollType)
if not ragdollType then return false end
self.RagdollType = ragdollType
return true
end
function ragdoll:Knockback(hit : BasePart,targetRoot : BasePart,Direction : Vector3,Duration)
local CharRagdoll = ragdoll.new(hit.Parent, {
CollisionsEnabled = true,
RagdollType = "Toggle",
AutoDestroy = true,
RemovalTime = Duration,
})
CharRagdoll:doRagdoll(true)
task.delay(Duration or 2,function()
CharRagdoll:doRagdoll(false)
end)
local BodyVelocity = Instance.new("BodyVelocity")
BodyVelocity.P = 5000
BodyVelocity.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
BodyVelocity.Velocity = Direction
BodyVelocity.Parent = targetRoot
local BodyAngularVelocity = Instance.new("BodyAngularVelocity")
BodyAngularVelocity.AngularVelocity = Direction
BodyAngularVelocity.Parent = targetRoot
game.Debris:AddItem(BodyVelocity,0.25)
game.Debris:AddItem(BodyAngularVelocity,0.2)
end
function ragdoll:Dismember(character: Model, limbName: string)
for _, obj in ipairs(character:GetDescendants()) do
if obj:IsA("BallSocketConstraint") then
if obj.Name:find(limbName:gsub("%s+", "")) then
obj:Destroy()
end
end
end
end
-- Starts the ragdoll simulation and removes it after the time specified.
function ragdoll:doRagdoll(toggle:boolean):boolean
local success, err = pcall(function()
initCollisionGroup()
self:debug(initRagdollFolder())
local characterRagdoll = getRagdollModel(self.RagdollType, self.Character)
self:debug(characterRagdoll)
local characterHumanoid = characterRagdoll:FindFirstChildOfClass("Humanoid")
self:debug(characterHumanoid)
if self.RagdollType == "Toggle" and toggle then
task.delay(self.RemovalTime or 10, function()
if self and self:isRagdolling() then
self:doRagdoll(false)
end
end)
end
if characterHumanoid then
characterHumanoid.PlatformStand = (self.RagdollType == "DeathBody") or (self.RagdollType == "Toggle" and toggle)
local animator = characterHumanoid:FindFirstChildOfClass("Animator")
for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
if track and track.Name ~= "AI_Track" then
track:Stop()
end
end
if self.RagdollType == "DeathBody" then
characterHumanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
characterHumanoid.BreakJointsOnDeath = false
characterHumanoid.Health = -math.huge
elseif self.RagdollType == "Toggle" and toggle == false then
characterHumanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
print("getting up")
local rootPart = characterRagdoll:FindFirstChild("HumanoidRootPart")
if rootPart then
rootPart.AssemblyLinearVelocity = Vector3.zero
rootPart.AssemblyAngularVelocity = Vector3.zero
end
end
end
local IMPACT_SPEED_THRESHOLD = 40
local lastImpactTime = 0
local IMPACT_COOLDOWN = 1
local HumanoidRootPart = characterRagdoll:FindFirstChild("HumanoidRootPart")
HumanoidRootPart.Touched:Connect(function(hit)
if hit:IsDescendantOf(characterRagdoll) then return end
local speed = HumanoidRootPart.AssemblyLinearVelocity.Magnitude
local now = os.clock()
if speed >= IMPACT_SPEED_THRESHOLD and (now - lastImpactTime) >= IMPACT_COOLDOWN then
lastImpactTime = now
Effect:createDebris(characterRagdoll,5,1,HumanoidRootPart.CFrame)
if #RagdollSoundTable > 0 then
local randomSound = RagdollSoundTable[math.random(1, #RagdollSoundTable)]:Clone()
randomSound.Parent = HumanoidRootPart
randomSound:Play()
game.Debris:AddItem(randomSound, randomSound.TimeLength + 0.1)
end
end
end)
--Ragdoll Wind
local HRP = characterRagdoll:FindFirstChild("HumanoidRootPart")
self.RagdollWindConnection = RunService.Heartbeat:Connect(function()
if not HRP then return end
local velocity = HRP.AssemblyLinearVelocity.Magnitude
if velocity < 100 then
if HRP:FindFirstChild("RagdollWind") then
HRP.RagdollWind:Destroy()
end
return
end
if not HRP:FindFirstChild("RagdollWind") then
local RagdollFX = Combat.RagdollWind:Clone()
RagdollFX.Name = "RagdollWind"
RagdollFX.Parent = HRP
RagdollFX.CFrame = HRP.CFrame
Util:Weld(RagdollFX, HRP)
end
end)
local lastVelocity = {}
RunService.Heartbeat:Connect(function()
for _, part in characterRagdoll:GetDescendants() do
if part:IsA("BasePart") then
lastVelocity[part] = part.AssemblyLinearVelocity.Magnitude
end
end
end)
for _, child in characterRagdoll:GetChildren() do
--RagdollSound
if self.CollisionsEnabled then
if child:IsA("BasePart") then
local box, weld = createOrGetCollisionBox(child)
if not self._ragdollCache[child] then
self._ragdollCache[child] = {}
end
if self._ragdollCache[child] and not self._ragdollCache[child].OldCollisionGroup then
self._ragdollCache[child].OldCollisionGroup = child.CollisionGroup
end
if self.RagdollType == "Toggle" then
box.CanCollide = toggle
box.Massless = not toggle
child.CollisionGroup = (toggle and "__ragdollColl") or self._ragdollCache[child].OldCollisionGroup
elseif self.RagdollType == "DeathBody" then
box.CanCollide = true
box.Massless = false
child.CollisionGroup = "__ragdollColl"
end
if self.DebugMode then
box.Transparency = 0.5
box.Material = Enum.Material.Plastic
box.Color = Color3.new(1,0,0)
child.Transparency = 0.5
end
end
end
end
for _, child in characterRagdoll:GetDescendants() do
if (child:IsA("LocalScript") or child:IsA("Script") or child:IsA("ForceField")) and self.RagdollType == "DeathBody" then
child:Destroy()
end
end
characterRagdoll.Parent = (self.RagdollType == "DeathBody" and initRagdollFolder()) or characterRagdoll.Parent
self:debug(characterRagdoll.Parent)
wait()
for _, child in characterRagdoll:GetDescendants() do
if child:IsA("BasePart") then
child.CustomPhysicalProperties = ((self.RagdollType == "DeathBody" or (self.RagdollType == "Toggle" and toggle))
and PhysicalProperties.new(self.Density, self.Friction, self.Elasticity))
or nil
if self.RagdollType == "DeathBody" then
child.CanQuery = false
child.CanTouch = false
end
if self.Player and RunService:IsServer() then
if (self.RagdollType == "Toggle" and toggle) or self.RagdollType == "DeathBody" then
child:SetNetworkOwner(nil)
else
child:SetNetworkOwnershipAuto()
if self.RagdollWindConnection then
self.RagdollWindConnection:Disconnect()
self.RagdollWindConnection = nil
end
if self.RagdollSoundConnection then
self.RagdollSoundConnection:Disconnect()
self.RagdollSoundConnection = nil
end
end
end
end
if child:IsA("Motor6D") then
if self.RagdollType == "Toggle" and self._ragdollCache[child] then
local cache = self._ragdollCache[child]
self._ragdollCache[child].Motor.Enabled = not toggle
self._ragdollCache[child].BallSocket.Enabled = toggle
if cache.BallSocket then
if toggle then
cache.BallSocket.Enabled = true
else
local socket = cache.BallSocket
local a0 = socket.Attachment0
local a1 = socket.Attachment1
socket:Destroy()
if a0 then
a0:Destroy()
end
if a1 then
a1:Destroy()
end
cache.BallSocket = nil
end
end
continue
end
local ball = join(child, self.TwistAngleRange)
self:debug(child)
self:debug(ball)
if self.RagdollType == "DeathBody" then
child.Enabled = false
ball.Enabled = true
else
if not self._ragdollCache[child] then
self._ragdollCache[child] = {}
end
if ball and child then
self._ragdollCache[child].Motor = child
self._ragdollCache[child].BallSocket = ball
end
child.Enabled = not toggle
ball.Enabled = toggle
end
end
end
if self.RagdollType == "DeathBody" then
local doFade, fadeTime = self.DoFadeOnRemovalReached, self.FadeTime -- after cleanup these are nil
task.delay(self.RemovalTime, function()
if doFade then
for _, child in characterRagdoll:GetDescendants() do
if child:IsA("BasePart") or child:IsA("Decal") or child:IsA("Texture") then
TweenService:Create(child, TweenInfo.new(fadeTime, Enum.EasingStyle.Linear), {
Transparency = 1
}):Play()
end
end
game.Debris:AddItem(characterRagdoll, fadeTime)
else
game.Debris:AddItem(characterRagdoll, 0)
end
end)
wait()
characterRagdoll.PrimaryPart.AssemblyLinearVelocity = self.Character.PrimaryPart.AssemblyLinearVelocity
characterRagdoll.PrimaryPart.AssemblyAngularVelocity = self.Character.PrimaryPart.AssemblyAngularVelocity
self:debug(characterRagdoll.PrimaryPart.AssemblyLinearVelocity)
self:debug(characterRagdoll.PrimaryPart.AssemblyAngularVelocity)
local tag = Instance.new("ObjectValue")
tag.Value = characterHumanoid
tag.Name = "_ragdoll"
tag.Parent = self.Character
game.Debris:AddItem(tag, 3)
end
end)
if success then
self._ragdolling = (self.RagdollType == "DeathBody" and true) or self.RagdollType == "Toggle" and toggle
end
if self.RagdollType == "DeathBody" then
for i,v in self.Character:GetDescendants() do
if v:IsA("BasePart") or v:IsA("Texture") or v:IsA("Decal") then
v.Transparency = 1
end
if v:IsA("BasePart") then
v.CanCollide = false
v.CanTouch = false
v.CanQuery = false
v.Anchored = true
end
if v:IsA("ForceField") then
v:Destroy()
end
end
end
self:debug(success)
self:debug(err)
if self.AutoDestroy and self.RagdollType == "DeathBody" then
self:destroy()
end
return success, err
end
function ragdoll:isRagdolling()
return self._ragdolling == true
end
function ragdoll.getRagdoll(id:string)
return ragdolls[id] or false
end
-- Deletes all the ragdolls inside the ragdoll folder.
function ragdoll.clearAll()
initRagdollFolder():ClearAllChildren()
end
return ragdoll