Need help with blood splatter

I found a blood splatter script on youtube, i’ve been editing it all day, I’ve been stuck on what I think is the most simple problem. I need help on making the blood splats only appeared when the player takes a certain amount of damage.

here’s the code.

-- // Settings
local blood_destroy_delay = 10
local blood_parts_per_hit = 4

-- // Services

-- External services
local tweenService = game:GetService("TweenService")

-- Default services
local playersService = game:GetService("Players")

-- // Variables
local bloodPart = script:WaitForChild("BloodPart")
local bloodParticles = script:WaitForChild("BloodParticles")

local bloodCache = workspace:FindFirstChild("BloodCache")

-- // Functions

-- Blood cache existing check
if not bloodCache then
    bloodCache = Instance.new("Folder")
    bloodCache.Name = "BloodCache"
    bloodCache.Parent = workspace
end

-- Tweening size function
local tweenPartSize = function(part, duration, direction, size)
    
    local tween = tweenService:Create(part, TweenInfo.new(duration, Enum.EasingStyle.Sine, direction), {Size = size})
    tween:Play()

    return tween
end

-- Creating blood part function
local createBlood = function(position)
    
    local randomSize = math.random(2, 20) / 10
    
    local bloodClone = bloodPart:Clone()
    bloodClone.Position = position + Vector3.new(0, 0.05, 0)
    bloodClone.Size = Vector3.new(randomSize, 0.1, randomSize)
    
    bloodClone.Parent = bloodCache
    
    if math.random(2) == 1 then
        bloodClone.BloodSound:Play()
    end
    
    return bloodClone
end

-- Expanding the blood part size function
local expandBlood = function(part)
    
    local randomIncrement = math.random(5, 10) / 10
    
    local tween = tweenPartSize(part, 5, Enum.EasingDirection.Out, Vector3.new(part.Size.X + randomIncrement, 0.1, part.Size.Z + randomIncrement))
    
    spawn(function()
        tween.Completed:Wait()
        tween:Destroy()
    end)
end

-- Cleaning the blood parts function
local deleteBlood = function(part)
    
    local tween = tweenPartSize(part, 0.5, Enum.EasingDirection.In, Vector3.new(0, 0.1, 0))
    
    spawn(function()
        tween.Completed:Wait()
        tween:Destroy()
        
        part:Destroy()
    end)
end

-- Raycasting function
local raycast = function(character, raycastOrigin, raycastDirection)
    
    local params = RaycastParams.new()
    params.FilterDescendantsInstances = {character, bloodCache}
    params.FilterType = Enum.RaycastFilterType.Blacklist
    params.IgnoreWater = true
    
    local raycastResult = workspace:Raycast(raycastOrigin, raycastDirection, params)
    
    if raycastResult then
        return raycastResult
    end
end

-- // Connections
playersService.PlayerAdded:Connect(function(player)
    player.CharacterAdded:Connect(function(character)
        
        local rootPart = character:WaitForChild("HumanoidRootPart")
        
        local humanoid = character:WaitForChild("Humanoid")
        local oldHealth = humanoid.Health
        
        local particlesClone = bloodParticles:Clone()
        particlesClone.Parent = rootPart
        
        humanoid.HealthChanged:Connect(function(health)
            if health < oldHealth then
                
                oldHealth = health
                
                spawn(function()
                    for i = 1, blood_parts_per_hit do
                        
                        local raycastOrigin = rootPart.Position + Vector3.new(math.random(-20, 20) / 10, 0, math.random(-20, 20) / 10)
                        local raycastDirection = Vector3.new(0, -8, 0)
                        
                        local raycastResult = raycast(character, raycastOrigin, raycastDirection)
                        
                        if raycastResult then
                            particlesClone:Emit(2)
                            
                            delay(0.5, function()
                                local newBlood = createBlood(raycastResult.Position)
                                expandBlood(newBlood)
                                
                                delay(blood_destroy_delay, function()
                                    deleteBlood(newBlood)
                                end)
                            end)
                        end
                        
                        wait(math.random(0.5, 2) / 10)
                    end
                end)
            else
                oldHealth = health
            end
        end)
        
    end)
end)
1 Like

this should work

local HealthLost
local DamageThreshold = 20 -- so if the player loses 20 hp or more, then itll activate.

humanoid.HealthChanged:Connect(function(health)
            if health < oldHealth then
               HealthLost = health - oldHealth -- calculates how much health they've lost
               if HealthLost >= DamageThreshold then  
                  oldHealth = health

So, it does work, but not the way I wanted it to work.
It does make the blood spill at a certain amount of damage, but the blood just continues to spill. I wanted to where like there would be NO blood at all, unless you they take a certain amount of damage.

In this script, it just makes the blood continue to spill when you get hit with a certain amount of damage.

U prob need to save the variables, and reset them… add some print statements to debug it… what is the full script you are currently running?

local Module = {}

local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local BloodAssets = ReplicatedStorage["BloodAssets"]
local BloodDecals = BloodAssets["Decals"]
local BloodSounds = BloodAssets["Sounds"]
local BloodParticles = BloodAssets["Particles"]
local BloodPrints = BloodAssets["BloodPrints"]

local Ignore = {workspace.Debris, workspace.LiveContainer}

local SMALL_SIZES = {Vector3.new(1, 0.062, 1), Vector3.new(1.5, 0.062, 1.5), Vector3.new(0.75, 0.062, 0.75)}
local BIG_SIZES = {Vector3.new(3, 0.062, 3), Vector3.new(4.152, 0.062, 4.152), Vector3.new(5.257, 0.062, 5.257)}
local WALL_ORIENTATIONS = {Vector3.new(0, 90, -90), Vector3.new(-45, 90, -90), Vector3.new(-90, 0, 0), Vector3.new(-45, -90, 90), Vector3.new(0, -90, 90), Vector3.new(45, -90, 90), Vector3.new(90, 180, 0), Vector3.new(45, 90, -90)}
local WEDGE_ORIENTATIONS = {Vector3.new(-0, -90, 172.875), Vector3.new(-5.032, -134.778, 174.949), Vector3.new(-7.125, 180, -180), Vector3.new(-5.032, 134.778, -174.949), Vector3.new(0, 90, -172.875), Vector3.new(5.032, 45.222, -174.949)}

local function GetRayPoints(Object, SizeY)
	local RayPoints, Length = {}, 0
	local c = Object:GetChildren()

	for _, RayPoint in ipairs(c) do
		if RayPoint:IsA("Attachment") and RayPoint.Name == "RayPoint" then
			Length = Length + 1
			RayPoint.Position = Vector3.new(RayPoint.Position.X, -SizeY, RayPoint.Position.Z)
			RayPoints[Length] = RayPoint
		end
	end
	return RayPoints, Length
end

local function BloodEffects(Splat, IsPuddle)
	coroutine.wrap(function()
		local SFX = {BloodSounds.Splat1, BloodSounds.Splat2, BloodSounds.Splat3}
		local RNG = math.random(1,3)
		local Sound = SFX[RNG]:Clone()
		Sound.Parent = Splat
		Sound:Play()
		task.wait(1)
		Sound:Stop()
	end)()

	coroutine.wrap(function()
		local RNG = math.random(1,3)
		local TWEENINFO = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0)
		local GOALS
		if IsPuddle then
			GOALS = {Size = BIG_SIZES[RNG]}
		else
			GOALS = {Size = SMALL_SIZES[RNG]}
		end

		local SizeTween = TweenService:Create(Splat, TWEENINFO, GOALS)
		SizeTween:Play()
	end)()

	coroutine.wrap(function()
		local RNG = math.random(1, #BloodDecals:GetChildren())
		Splat.Decal.Texture = BloodDecals[RNG].Decal.Texture
	end)()

	coroutine.wrap(function()
		task.wait(Random.new():NextNumber(3, 7))
		local TWEENINFO = TweenInfo.new(2, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut, 0, false, 0)
		local GOALS = {Transparency = 1}
		local TransparencyTween = TweenService:Create(Splat.Decal, TWEENINFO, GOALS)
		TransparencyTween:Play()
		TransparencyTween.Completed:Wait()
		Splat:Destroy()
	end)()
end

function Module.Bleed(Drop, TargetPart, BleedTime, BloodDropRate, IsPuddle)
	local Counter = 0
	local RandomVelocity = Vector3.new(math.random(-15,15),math.random(-15,15),math.random(-15,15))
	
	while Counter < BleedTime do 	
		
		local CreatedTick = tick()
		local CurrentTick = tick()
		local Drop = Drop:Clone()
		Drop.CanCollide = false
		Drop.CanQuery = false
		
		local Velocity = Drop.BodyVelocity

		Drop.Parent = workspace.Debris
		Drop.Position = TargetPart.Position

		Velocity.MaxForce = Vector3.new(50000, 50000, 50000)
		Velocity.P = Vector3.new(100000)
		Velocity.Velocity =  Vector3.new(math.random(-15, 15), math.random(-6,-5), math.random(-15, 15))

		task.wait()
		Velocity.Velocity = Vector3.new(0,0,0)
		Velocity.MaxForce = Vector3.new(0,0,0)
		Velocity.P = Vector3.new(0,0,0)
		Counter += 1 
		
		coroutine.wrap(function()
			task.wait(.45)
			if Drop then
				Drop:Destroy()
			end
		end)()
		
		local RaycastData = RaycastParams.new()
		RaycastData.FilterType = Enum.RaycastFilterType.Blacklist
		RaycastData.FilterDescendantsInstances = Ignore
		RaycastData.IgnoreWater = true	

		local RayPoints, Length = GetRayPoints(Drop, BIG_SIZES[2])
		local PosData = {}

		local HasHit = false
		
		coroutine.resume(coroutine.create(function()
			while Drop and Drop.Parent and not HasHit do
				for i = 1, Length do
					local RayPoint = RayPoints[i]
					local NewPos = RayPoint.WorldPosition
					local OldPos = PosData[RayPoint]

					if not OldPos then
						OldPos = NewPos
						PosData[RayPoint] = NewPos
					end

					local RaycastResults = workspace:Raycast(NewPos, (NewPos - OldPos), RaycastData)

					if not RaycastResults or HasHit then PosData[RayPoint] = NewPos continue end

					local RayHit = RaycastResults.Instance
					local RayNormal = RaycastResults.Normal

					if not RayHit.CanCollide or HasHit then PosData[RayPoint] = NewPos continue end
					
					HasHit = true
					
					coroutine.wrap(function()
						Drop:Destroy()
					end)()
					
					local Blood = BloodPrints.Puddle:Clone()	
					if Blood then
						Blood.Anchored = true
						Blood.CanCollide = false
						Blood.CanTouch = false
						Blood.Position = RaycastResults.Position
						Blood.CFrame = CFrame.new(Blood.Position, Blood.Position + RayNormal) * CFrame.Angles(math.rad(90),0,0)
						if RayHit.CollisionGroup == "Floor" then
							if not RayHit:IsA("WedgePart") then
								Blood.Orientation += Vector3.new(0, Random.new():NextNumber(-180, 180), 0)
							else
								Blood.Orientation = WEDGE_ORIENTATIONS[math.random(1, #WEDGE_ORIENTATIONS)]
							end
						elseif RayHit.CollisionGroup == "Wall" then
							Blood.Name = "BloodPrint"
							Blood.Orientation = WALL_ORIENTATIONS[math.random(1, #WALL_ORIENTATIONS)]
						end
						Blood.Decal.ZIndex = Counter
						Blood.Parent = workspace.Debris

						BloodEffects(Blood, IsPuddle)
					end

				end
				RunService.Heartbeat:Wait()
			end
			
		end))
		
		if BloodDropRate == 0 then
			RunService.Heartbeat:Wait()
		else
			task.wait(BloodDropRate)
		end
		
	end
	
end

return Module