Ragdoll Effects not happening in Real Time

You can write your topic however you want, but you need to answer these questions:

  1. 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

  2. What is the issue? Include screenshots / videos if possible!

  3. 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