I have damage indicators for my game. I’m getting characters through the characteradded event, but that doesn’t work for nonplayer-humanoids. I want to be able to use damage indicators for NPCs as well. How could I get their humanoids?
game.Players.PlayerAdded:Connect(function(plr)
plr.CharacterAdded:Connect(function(char)
local Hum = char.Humanoid
local CurrentHealth = Hum.Health
Hum.HealthChange:Connect(function(Health)
if Health < CurrentHealth and Hum:GetState() ~= Enum.HumanoidStateType.Dead then
local Damage = math.floor(CurrentHealth - Health)
local Indicator = game:GetService("ReplicatedStorage").Assets.Effects.Indicator:Clone()
Indicator.Parent = game:GetService("Workspace")
Indicator.Num.TextLabel.Text = tostring(Damage)
Indicator.CFrame = CFrame.new(char.HumanoidRootPart.CFrame) * CFrame.new(math.random(-2,2), math.random(-2,2), math.random(-2,2))
coroutine.resume(coroutine.create(function()task.wait(.2)Indicator:Destroy()end))
end
CurrentHealth = Hum.Health
end)
end)
end)
Have a onCharacterAdded() function and use that with PlayerAdded, and then CharacterAdded.
For the NPCs just use the same function. How you can do it is just tag them with CollectionService, use the CollectionService:GetInstanceAddedSignal(tag) event and when an NPC gets added it will run the function on the NPC. Also don’t forget to loop the GetTagged function with your tag just in case anything gets missing (if you use this event once, it shouldn’t). You obviously need to tag all of the NPCs but that should be very easy.
local Characters = {}
for i,v in pairs (game:GetService("Workspace"):GetDescendants()) do
task.wait()
if v:FindFirstChild("Humanoid") ~= nil then
local Char = table.find(Characters,v,1)
if Char == nil then
table.insert(Characters,v)
end
end
end
Script to define all characters, also if you want to update it when something added then use this script.
local Characters = {}
local function DefineAllCharacters()
table.clear(Characters)
for i,v in pairs (game:GetService("Workspace"):GetDescendants()) do
task.wait()
if v:FindFirstChild("Humanoid") ~= nil then
local Char = table.find(Characters,v,1)
if Char == nil then
table.insert(Characters,v)
end
end
end
end
DefineAllCharacters()
game:GetService("Workspace").DescendantAdded:Connect(DefineAllCharacters)
So when any player joined the game their character is added to workspace and also the NPCs are in workspace, so if you get all the children of workspace (or descendent if you have NPC in folders) you can then check if those objects that you got in workspace (using a for loop) have humanoids and if so add that object to a table
This script only checks the models that are the workspace’s children. If the NPCs are placed inside a folder, it will not be able to check them as it will see the “v” as the Folder, not as the NPC model. So :GetDescendants() will work better with your script than :GetChildren()
Though, the NPCs that are supposed to be hit can be grouped into one folder and then that folder can have :GetChildren() ran on it instead. This is better performance-wise
local Characters = {}
local Humanoids = {}
local function DefineAllCharacters()
table.clear(Characters)
table.clear(Humanoids)
for i,v in pairs (game:GetService("Workspace"):GetDescendants()) do
task.wait()
if v:FindFirstChild("Humanoid") ~= nil then
local Char = table.find(Characters,v,1)
local Hum = table.find(Humanoids,v:FindFirstChild("Humanoid"),1)
if Char == nil and Hum == nil then
table.insert(Characters,v)
table.insert(Humanoids,v:FindFirstChild("Humanoid"))
end
end
end
end
DefineAllCharacters()
game:GetService("Workspace").DescendantAdded:Connect(DefineAllCharacters)
Np, thx for advise about performans, you also got error in that i use GetChildren(), i used GetDescendants() already, but i forgot about DescendantAdded and placed ChildAdded event instead(i changed it already).
Your use of task.wait() in it drastically slows down your code. As it is going through every descendant of workspace, it is likely that there would be 100s if not 1000s of parts. task.wait() waits 1/60 of a second. Per 600 parts that is 10 seconds of processing time for it, which may be too long for OP’s use case.
You can probably get away with just not having it.
If lag is a concern, there is an optimisation you can try using v:FindFirstChild(“Humanoid”), check if the instance itself is the humanoid (v:IsA(“Humanoid”)). Then replace v with v.Parent later in the script. This just removes the need for the server to loop through each part’s children, which would cause a lot of lag.