A better way to check if something is inside a character

Hello,
I made some crossbows recently but I’ve ran into a problem that I solved but in an inefficient way and I’m here to see if there’s a better way to check if something is a child of the character with out adding multiple if’s to check if the parent is an accessory or a model etc etc, here’s the script if it helps, Any help is appreciated.

Damage script:

if hit.Parent:FindFirstChild("Humanoid") then
		print("Player")
		local char = hit.Parent
		print("In Radius")
		hit.Parent:FindFirstChild("Humanoid"):TakeDamage(damage)
	    char.Head.Hit:Play()
	elseif hit.Parent:IsA("Accessory") or hit.Parent:IsA("Hat") then
		local char = hit.Parent.Parent	
		char.Humanoid:TakeDamage(damage)
		char.Head.Hit:Play()
	end
1 Like

Depending on how fast your arrow flies, you might want to stay away from Touched (if it’s fast). It’s better to use a physics simulation and detect hits with raycasts. This post might give you some pointers.

Regardless of what you use, you can’t really get around having if-checks. If your characters are the default characters (or you are certain that you never put a model inside them), this snippet will give you the humanoid object from a part:

local hum = hit:FindFirstAncestorWhichIsA("Model"):FindFirstChildWhichIsA("Humanoid")

If you need the character model, make sure to use hum.Parent as hum will be nil if the part is not part of a character (so you can get away with a single if-check: if hum then).

3 Likes

I should’ve specified, I was talking in general, For Instance swords and such.

You can still edit this code with the line I provided to shorten it down by a bit.

local hum = hit:FindFirstAncestorWhichIsA("Model"):FindFirstChildWhichIsA("Humanoid")
if hum then
    hum:TakeDamage(damage)
    hum.Parent.Head.Hit:Play()
end

Remember that this (but also your) code would error if the character doesn’t have a head; make sure that can never happen or add another if-check making sure it’s there before indexing it.

Does “FindFirstAncestorWhichIsA” return every parent? I’m talking if the bullet or the sword hit a model that was welded onto the character

Show

In that example the sword would deflect a bullet if it hits the sword straight on, if you use my code at least. A sword would probably just slice through the player anyway so it’s no big deal.

Im talking in general because the whole purpose of this topic is to find a way to get the humanoid even if the touched part was in 100 models

In that case you would either want to loop through all existing characters, or use recursion/iteration to get to the bottom-most model that has a humanoid inside it.

I’d do the latter since it seems like the appropiate solution for an event that can happen multiple times per second.

local m = hit.Parent
while not m:FindFirstChild("Humanoid") and m.Parent ~= game do
    m = m.Parent
end
local hum = m:FindFirstChild("Humanoid")
6 Likes

But wouldnt that get the parent of the model that got touched? and not the character of the part that touched it?

The script will keep moving up in the game hierachy (starting from hit) until m is a model with a humanoid inside it - a character.

1 Like

I was confused since it has “script.Parent” and not “hit.Parent” well thanks for clearing it up.

bro, tysm for it i was trying to find it and i found, nice job

If you are still wishing to do this, there is a much better and more optimised way to do this, that being the ZonePlus Module: ZonePlus v3.2.0 | Construct dynamic zones and effectively determine players and parts within their boundaries
Depends if this will be applicable in your situation, but in most cases, its far better to use this than the .Touched event.