HealthChanged event not firing quick enough

Basically, the HealthChanged event doesn’t fire as quickly as I want it to run, which causes inaccurate damage indicators.

(accurate event (WHAT I WANT)) (this works randomly)

(nonaccurate event (THE THING IM STUCK AT))


(FYI, this doesn’t just work after the first time i shoot, this can also happen the first time i shoot)

(sorry i used a lot of warns, it stands out more than print)


On the accurate event, the warn("TAKEN DAMAGE") appears in the output around the 250 mark.

However, on the nonaccurate damage, it fires warn("TAKEN DAMAGE") appears far less than the 250 mark. (and no, hitting the other dummies did NOT affect the event)

Also, FYI, each NPC has their own, unique server script with the exact code that has the HealthChanged event, so they cannot interfere with one another.
→ there are no client scripts that fire to that server event
→ a module script, that was called by a server script, called by a local script runs the code where the player is shooting.

→ there are 250 bullets per reload, and each bullet shoots out per 0.03 seconds.
→ -> im sure that the amount of bullets being spawned simultaneously doesn’t affect the HealthChanged, as it worked as I wanted it to work at least once.


code:

(i’ll move some parts of the code to another section, as i personally think they don’t have anything to do with the problem.)

local char = script.Parent

local humanoid = char:WaitForChild("Humanoid")
local currentHealth = humanoid.Health

local tweenService = game:GetService("TweenService")
local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Circular, Enum.EasingDirection.InOut)

local start = false

local damageIndicatorGui
local damageIndicatorLabel
local numVal
local StrokeUI

local hasChanged

local ONLYONCE = false

local timer = 5;
local lastHp = humanoid.Health;

coroutine.wrap(function()
	
	while humanoid.Health > 0 do
		repeat
			wait(1)
			if start == true then
				timer -= 1
			end
		until timer <= 0
		warn("ENDED!!")
		
			repeat wait(0.5) until damageIndicatorGui ~= nil
			local tweenInfo2 = TweenInfo.new(
				0.7, -- The time the tween takes to complete
				Enum.EasingStyle.Circular, -- The tween style.
				Enum.EasingDirection.In, -- EasingDirection
				0, -- How many times you want the tween to repeat. If you make it less than 0 it will repeat forever.
				false, -- Reverse?
				0 -- Delay
			)

			local Tween = tweenService:Create(damageIndicatorLabel, tweenInfo2, {Rotation = 360}) -- Creates the tween with the TweenInfo and what properties you want to change
			Tween:Play() -- Plays the tween

			local guiDownTween = tweenService:Create(damageIndicatorGui, tweenInfo, {StudsOffset = damageIndicatorGui.StudsOffset + Vector3.new(0, -1, 0)})

			guiDownTween:Play()

			local textFadeTween = tweenService:Create(damageIndicatorLabel, tweenInfo, {TextTransparency = 1})
			local sTween = tweenService:Create(StrokeUI, tweenInfo, {Transparency = 1})

			textFadeTween:Play()
			sTween:Play()

			game:GetService("Debris"):AddItem(damageIndicatorGui, 0.3)
			start = false
		timer = 5
	end
end)() 

humanoid.HealthChanged:Connect(function(health)
	if health < currentHealth and humanoid:GetState() ~= Enum.HumanoidStateType.Dead then
		warn("TAKEN DAMAGE")
		
		if(currentHealth < lastHp) then
			timer = 5 
		else
			lastHp = currentHealth
		end
		
		start = true

		local healthLost = currentHealth - health
		
		if char.HumanoidRootPart:FindFirstChild("DAMAGEINDICATEBILL") then
			damageIndicatorLabel = char.HumanoidRootPart:FindFirstChild("DAMAGEINDICATEBILL").DAMAGEINDICATE
			numVal = char.HumanoidRootPart:FindFirstChild("DAMAGEINDICATEBILL").DAMAGEINDICATE.DAMAGE
			hasChanged = char.HumanoidRootPart:FindFirstChild("DAMAGEINDICATEBILL").DAMAGEINDICATE.hasChanged
			damageIndicatorGui = char.HumanoidRootPart:FindFirstChild("DAMAGEINDICATEBILL")
			StrokeUI = damageIndicatorLabel.UIStroke
			
			ONLYONCE = true
		else
			
			warn("BE ONLY HERE ONCE")
			
			
			numVal = Instance.new("NumberValue")
			numVal.Name = "DAMAGE"
			
			hasChanged = Instance.new("BoolValue")
			hasChanged.Name = "hasChanged"
			
			damageIndicatorGui = Instance.new("BillboardGui")

			damageIndicatorGui.Name = "DAMAGEINDICATEBILL"
			damageIndicatorGui.AlwaysOnTop = true

			damageIndicatorGui.Size = UDim2.new(1.5, 0, 1.5, 0)

			local offsetX = math.random(-10, 10)/10
			local offsetY = math.random(-10, 10)/10
			local offsetZ = math.random(-10, 10)/10
			damageIndicatorGui.StudsOffset = Vector3.new(offsetX, offsetY, offsetZ)
			
			StrokeUI = Instance.new("UIStroke")
			StrokeUI.Thickness = 2.7
			StrokeUI.Color = Color3.new(0, 0, 0)	
			
			damageIndicatorLabel = Instance.new("TextLabel")
			damageIndicatorLabel.Name = "DAMAGEINDICATE"
			
			StrokeUI.Parent = damageIndicatorLabel
			
			damageIndicatorLabel.AnchorPoint = Vector2.new(0.5, 0.5)
			damageIndicatorLabel.Position = UDim2.new(0.5, 0, 0.5, 0)
			
			damageIndicatorLabel.Parent = damageIndicatorGui

			damageIndicatorLabel.Size = UDim2.new(0, 0, 0, 0)

			damageIndicatorGui.Parent = char.HumanoidRootPart

			damageIndicatorLabel.TextScaled = true
			damageIndicatorLabel.BackgroundTransparency = 1
			damageIndicatorLabel.Font = Enum.Font.GothamBold
			
			
			numVal.Parent = damageIndicatorLabel
			numVal.Value = 0
			
			hasChanged.Parent = damageIndicatorLabel
			
			damageIndicatorLabel:TweenSize(UDim2.new(1, 0, 1, 0), "InOut", "Quint", 0.3)
			
		end
		
		coroutine.resume(coroutine.create(function()
			numVal.Value = numVal.Value + healthLost
		end))
		
		local ValueOfHealthLost = numVal.Value
		
		local ts = game:GetService("TweenService")
		
		local ORIGINALnumVal = numVal.Value
		
		damageIndicatorLabel.Text = string.format("%0.2f", ValueOfHealthLost)
		
		hasChanged.Value = true
		
		local guiUpTween = tweenService:Create(damageIndicatorGui, tweenInfo, {StudsOffset = damageIndicatorGui.StudsOffset + Vector3.new(0, 0.05, 0)})
		
		guiUpTween:Play()
	end

	currentHealth = humanoid.Health
end)

TEXTCOLOR TWEENING:

coroutine.resume(coroutine.create(function()
			if ValueOfHealthLost <= 22.5 then
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
					{TextColor3 = Color3.fromRGB(255, 69, 69)} 
				):Play()
			elseif ValueOfHealthLost <= 48.5 then
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
					{TextColor3 = Color3.fromRGB(255, 150, 101)} 
				):Play()
			elseif ValueOfHealthLost <= 73.5 then
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
					{TextColor3 = Color3.fromRGB(188, 255, 65)} 
				):Play()
			elseif ValueOfHealthLost <= 98.5 then
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
					{TextColor3 = Color3.fromRGB(149, 200, 255)} 
				):Play()
			elseif ValueOfHealthLost <= 123.5 then
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
					{TextColor3 = Color3.fromRGB(146, 161, 255)} 
				):Play()
			elseif ValueOfHealthLost <= 148.5 then
				
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
					{TextColor3 = Color3.fromRGB(255, 197, 255)} 
				):Play()
			elseif ValueOfHealthLost <= 173.5 then
				ts:Create(
					damageIndicatorLabel, -- instance
					TweenInfo.new(
						2, -- speed
						Enum.EasingStyle.Circular, -- style
						Enum.EasingDirection.Out, -- direction
						0, -- repeat
						false, -- boolean (reverse)
						0 -- delay
					),
						{TextColor3 = Color3.fromRGB(255, 255, 255)} 
				):Play()
			end
		end))

Any help is appreciated. (sorry for the long code, i’m VERY unorganized.)

I’m not sure about your issue yet but,
Are you sure that every bullet are registered at first ? If the event is not triggered might be because the script that deal damage don’t register every bullet hitting your dummy… that’s just speculation but that’s the only way i can imagine since sometime it work perfectly, sometime not.
So i don’t think it has something to do with the healthChanged but more with your bullet register.

apologies if it’s not clear

The bullets deal damage first on a seperate script in ServerScriptService,
then once the humanoid from the NPC detects that it has taken damage from the bullet, it fires the HealthChanged event.
→ it still takes damage without the HealthChanged event firing.
→ it could be that it detects so many HeathChanged events firing it prevents some from firing to stop lag, however, it still doesn’t argue the recording of it working

→ also each bullet is hitting the NPC and dealing damage. If you want the code, let me know, although, i dont think thats the problem

So if you were to insert a print("Bullet Hit") as soon a bullet hit the dummy, you would be supposed to have 250 print since you got 250 bullet in a magazine. Have you tested this in order to eliminate this possibility ?

edit: hold on, i didn’t read properly your post

So that mean,
Your script detected let’s say only 100 damange on your 250,
but in the workspace, the actual health is much lower, right ?

Yes – in the video (unaccurate) the health (at the top right of the NPC’s head) says that its
461/500 (~39 damage);
but the indicator says that the NPC has taken ~12.20 damage

when i tested it out more, when I shoot all the bullets, it deals around a max of 70 damage to the NPC.
even on 70 damage, it still shows around 12.20 damage.

then it might be the engine, not sure we can bruteforce this.
So the best way would be to change the way you detect the damage.
Maybe a loop that would check if the health is the same as 0.01 second before, and then trigger if it’s not…

i’ll find a way to get around that, but it’s gonna take me a while to try inputting each solution, im thinking of using server script to server script communication (when the bullets hit and deal damage, ill make something that the indicate script will try to detect)

also, thanks for helping me out, if it works, i’ll mark yours as a solution.

edit: kinda worried that your solution might cause lag, as it is running a loop forever with a wait of 0.01 – other players can switch into the character in the video, so multiple loops playing at the same time might cause lag

another edit: kinda realized that i have to do a loop to detect something forever, so ill try out your solution.

apparently it worked – apparently since i dont have lots of stuff running at once (yet), it shouldn’t cause much lag.

some times it may be slow, but it still gives the ACTUAL (im happy now) damage!!!


so i tried to do what you said,

local prevHealth

coroutine.resume(coroutine.create(function()
	while true do
		prevHealth = humanoid.Health
		wait(0.1)
	end
end))

– – DAMAGE INDICATE CODE

while true do
	task.wait(0.03)
	if prevHealth ~= humanoid.Health then  -- pretty sure the rest is predictable

just wanted to say thanks for helping me with this : ) can’t thank you enough

1 Like

Your welcome, and good luck with your project ! it’s already looking nice

1 Like

thanks so much : )
but honestly you helped me make it better with helping me

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.