How can I loop through the parents of an instance without any delay?

Hi, I have an issue. I’m making a combat engine, and I’ve gotten most thing working such as bullets, but there is one issue I came across just now and cant find solutions for.

Whenever the bullet hits an object, it cant detect if it is inside a character [not just players but NPCs too], making it so it can’t damage. I know why, which is because my playermodels are made up of quite a few parts, and they are fairly deep inside the characters model. Here’s how they look.

[REMOVED]

And back to the question, how would I loop through all the parents of an instance parents without any delay? [a repeat until loop worked great, but since I had to use a wait() it caused a noticeable delay in damaging the players.]

Yes i tried the following :

instance.Parent:FindFirstChild("Humanoid") or instance.Parent.Parent:FindFirstChild("Humanoid") --so on

but it errored mainly because it kept trying to get the parent of Game, and its also not the best way to do it.

Quick Example incase you still don’t get what I’m trying to say :
EXAMPLE

Thanks. Sorry for the long post btw.

I believe you can make use of IsDescendantOf() for this purpose, not sure internally how this works but it’s worth a try.

https://developer.roblox.com/en-us/api-reference/function/Instance/IsDescendantOf

Also to add why were you having to use a wait within your “repeat until” loop?

Without having a wait, it’d do the same as a while true do loop where it freezes the game.

You can also do a recursive function for this purpose. I’ve done it for a vehicle chassis debugging plugin to search for the main parent script.

local function searchUntilPlugin(currentAsset)
	if currentAsset.Parent.Name ~= "Plugins" and currentAsset.Parent ~= game.Workspace then
		return searchUntilPlugin(currentAsset.Parent)
	else
		return currentAsset
	end
end

Just from looking at it, it looks like it’d solve my issue! I’ll test before I say anything else.

1 Like

Ok, so it works but now the issue is it keeps damaging the humanoid over and over, even just from one shot. And idea what causes this?
My implementation :
Impl

Heres what I mean :
[REMOVED]

Probably you have some boolean that isnt registering the fact that it was hit once. Since the getHuman() method you adapted from my suggestions shouldn’t be causing trouble. Also touched events tend to fire multiple times if thats what your using.

function GetDescendants(obj : Instance)
  local t = {}
  while obj.Parent do
    obj = obj.Parent
    table.insert(t, obj)
  end
  return t
end

I’m using raycast bullets so its not that, but I think you’re right about the boolean.

Do some debug lines for testing purposes to see if its registering the hit more than once.

:wave:t2:KONNICHIWA!
Assuming your humanoids don’t have additional models in them then you can just use

:FindFirstAncestorOfClass()
function getHuman(instance)
	local Character = instance:FindFirstAncestorOfClass("Model")
	if Character and Character:FindFirstChild("Humanoid") then
		return Character.Humanoid
	end
end

Good luck my guy.

They do indeed have models, but I think combining your method and also Boston’s method, I can come up with something.

:wave:t2:Kon’nichiwa again!
In that case you can just use :FindFirstAncestor and make a whitelist for players and npc’s like this:

local NPC_Names = {"Idk", "What_your", "NPC's","Are called"}
function WhiteList()
	local WhiteL = {}
	local Players = game.Players:GetPlayers()
	for i,Player in pairs(Players) do
		table.insert(WhiteL,Player.Name)
	end
	for i,NPCName in pairs(NPC_Names) do
		table.insert(WhiteL,NPCName)
	end
	return WhiteL
end

function getHuman(instance)
	local WL = WhiteList()
	local Character = nil
	for i, CheckWL in pairs(WL) do
		if instance:FindFirstAncestor(CheckWL) then
			Character = instance:FindFirstAncestor(CheckWL)
			break
		end
	end
	if Character ~= nil and Character:FindFirstChild("Humanoid") then
		return Character.Humanoid
	end
end

This should also easily allow you to base the whitelist on other factors such as the players team with a bit of tweaking. It’s much better than the method I suggested before!

This should properly do exactly what you are asking about! Let me know what you think!

Wouldn’t quite help, especially considering there will be shooter bots with randomly generated names. Thanks though.

It would still work, just use whatever method you normally use to detect the bots.

Bots are in a organized folder?

local BotFolder = workspace.BotFolder
function WhiteList()
	local WhiteL = {}
	local Players = game.Players:GetPlayers()
	for i,Player in pairs(Players) do
		table.insert(WhiteL,Player.Name)
	end
	for i,Bot in pairs(BotFolder:GetChildren()) do
		table.insert(WhiteL,Bot.Name)
	end
	return WhiteL
end

Bots are not in a folder?
If the bots are not organized into a folder, but are just spawned into workspace; then you can just check for whatever unique item they have, such as bool in the character that regular players don’t have.

function WhiteList()
	local WhiteL = {}
	local Players = game.Players:GetPlayers()
	for i,Player in pairs(Players) do
		table.insert(WhiteL,Player.Name)
	end
	for i,Bot in pairs(workspace:GetChildren()) do
		if Bot:FindFirstChild("WhateverTheItemInTheBotsIsCalled") then
			table.insert(WhiteL,Bot.Name)
		end
	end
	return WhiteL
end

I was just thinking you would say that!
All bases covered?

Ah, never mind! This worked perfectly, it was just an issue with my raycast which has been fixed. It detected multiple hits on a part at once, but I fixed it and now the damage works great with any humanoid. Thanks a lot for the help you guys!

Removed pictures and videos for classification purposes

1 Like
local starterChar = script:FindFirstAncestor("StarterCharacter")
local starterChatDescendants = starterChar:GetDescendants()

for i, v in pairs(starterChatDescendants) do
	--do stuff with the descendants of starter char
end

Place the script inside the part itself, this is likely the simplest way to achieve this task.