Issue with weapon hitbox only hitting 1 enemy instead of multiple

I found this tutorial on youtube on how to make hitboxes for weapons. However, the hitbox for my weapon only does damage to the first humanoid it comes into contact with.
video of the issue:

What do i need to change in my script for my weapon hitbox to deal damage to every humanoid it touches every swing?

local tool = script.Parent
local bat = tool.BatModel
local damage_re = tool:WaitForChild("SwingEvent")
local hitsound = bat.BatHit

local connection = nil

local function inflict_damage(other_object)
	if connection then
		connection:Disconnect()
		local humanoid = other_object.Parent:FindFirstChild("Humanoid")
		
		if humanoid then
			humanoid:TakeDamage(25)
		end
		hitsound:Play()
	end
end

damage_re.OnServerEvent:Connect(function()
	local hitbox = Instance.new("Part",tool)
	hitbox.Size = Vector3.new(1,5,1)
	hitbox.CanCollide = false
	hitbox.Massless = true
	hitbox.Transparency = 1 --debug

	local weld = Instance.new("Weld",hitbox)
	weld.Part0 = bat
	weld.Part1 = hitbox
	game.Debris:AddItem(hitbox,0.4)

	connection = hitbox.Touched:Connect(inflict_damage)
end)

(im super new to scripting so forgive me if i dont understand something)

1 Like

So what’s happening is that when you hit someone, you are turning off the detector. This is good because it won’t let you hit them more than once. But it’s bad because then it won’t detect new things.

You have to keep track of who you have hit to ignore them if it hits them again. The easiest way to do that is generally a dictionary. I highly recommend looking into what they are. I can give you the solution directly if the educational experience isn’t a part of what you are after (or if you get stuck and NEED a reference), but I will only do so if you ask so you can give it a shot yourself first. It will likely be more educational to try even if you don’t succeed this time, before attempting to reference a working design. Tutorials while useful often also can hinder learning by making it a tad to easy to just copy what they do. So solving stuff like this on your own is generally a valuable part of following tutorials.

3 Likes

This line is the Touched connection for the added hitbox:

connection = hitbox.Touched:Connect(inflict_damage) -- it calls the inflict_damage function

As soon as the Touched connection is made and inflict_damage function called, the first thing the function does is disconnect:

	if connection then
		connection:Disconnect()

So it will only ever damage the first Humanoid it hits.

2 Likes

i tried to use a dictionary to fix it but i didnt do it right

local function inflict_damage(other_object)
	if connection then

		local hitlist = {
			name = "",
		}
		local humanoid = other_object.Parent:FindFirstChild("Humanoid")
		
		if humanoid then
			hitlist.name = humanoid.Parent.Name
			humanoid:TakeDamage(25)
		end
		for i in hitlist do
			hitsound:Play()
		end
		connection:Disconnect()
	end
end

i did this for my inflict_damage() function and i had the same result, could you tell me how to fix it with dictionaries?

1 Like

Yeah. So first, we actually have to move the dictionary outside (and above) of the function. This is because this function only runs when someone was hit and everything created inside it gets deleted after it runs.

[read the comments, a lot of helpful description is there in each block of code]

local hitlist = {} --creates dictionary
local function inflict_damage(other_object)
    --...

Then inside the inflict_damage function we need to check if someone was already hit before moving inside. I see you tried storing a name, but if people had the same name, it would think you already hit them. So we are actually going to store the parent of the part you hit.

local function inflict_damage(other_object)
    if(not hitlist[other_object.Parent]) then --check if the parent has already been seen
        --only move on to hit them if they are NOT in the hitlist
    end
end

Now we can move onto filling out the part that looks for a humanoid and damages them. We also need to add other_object.Parent to the hitlist if we do damage them.

local function inflict_damage(other_object)
    if(not hitlist[other_object.Parent]) then --check if the parent has already been seen
        local humanoid = other_object.Parent:FindFirstChild("Humanoid")
        if humanoid then
            hitlist[other_object.Parent] = true --This can be anything other than nil or false.  It's the value we get back when we ask what is inside hitlist[other_object.Parent].  It will be nil if it doesn't exist, but will be true in this case if it does exist in the hitlist.
            humanoid:TakeDamage(25)
            hitsound:Play() -- let's play this when they get damaged instead of trying to loop.
        end
        --We don't disconnect here anymore.  If we disconnect, then we will only run this function on the first block we hit, but we want it to run on all of them.
    end
end

And finally we just need to make sure we clear hitlist every time we activate the weapon so we don’t accidentally make it so that it will only ever damage a character one time.

damage_re.OnServerEvent:Connect(function()
	local hitbox = Instance.new("Part",tool)
	hitbox.Size = Vector3.new(1,5,1)
	hitbox.CanCollide = false
	hitbox.Massless = true
	hitbox.Transparency = 1 --debug

	local weld = Instance.new("Weld",hitbox)
	weld.Part0 = bat
	weld.Part1 = hitbox
	game.Debris:AddItem(hitbox,0.4)

    hitlist = {} --resets hitlist by creating a new list
        
	connection = hitbox.Touched:Connect(inflict_damage)
end)

Putting that all together we get

local tool = script.Parent
local bat = tool.BatModel
local damage_re = tool:WaitForChild("SwingEvent")
local hitsound = bat.BatHit

local connection = nil --we technically don't need this anymore, but since we set something to it later we have to include it or stop using it

local hitlist = {}

local function inflict_damage(other_object)
    if(not hitlist[other_object.Parent]) then --check if the parent has already been seen
        local humanoid = other_object.Parent:FindFirstChild("Humanoid")
        if humanoid then
            hitlist[other_object.Parent] = true --This can be anything other than nil or false.  It's the value we get back when we ask what is inside hitlist[other_object.Parent].  It will be nil if it doesn't exist, but will be true in this case if it does exist in the hitlist.
            humanoid:TakeDamage(25)
            hitsound:Play()
        end
        --We don't disconnect here anymore.  If we disconnect, then we will only run this function on the first block we hit, but we want it to run on all of them.
    end
end

damage_re.OnServerEvent:Connect(function()
	local hitbox = Instance.new("Part",tool)
	hitbox.Size = Vector3.new(1,5,1)
	hitbox.CanCollide = false
	hitbox.Massless = true
	hitbox.Transparency = 1 --debug

	local weld = Instance.new("Weld",hitbox)
	weld.Part0 = bat
	weld.Part1 = hitbox
	game.Debris:AddItem(hitbox,0.4)

    hitlist = {} --resets hitlist by creating a new list
        
	connection = hitbox.Touched:Connect(inflict_damage)
end)

That’s a lot of changes, so hopefully I didn’t mix something up there. I can’t really test it to ensure it works but I can help you debug if there are problems.

3 Likes

the code works perfectly, tysm for the fix and also explaining what each thing does!

also i want to make it clear that the reason i looped the sound in my code was because i was trying to add each enemy hit into a list, then deal damage AND play the sound for each element (element being the enemies who were hit). the only reason why it was just the sound is because i couldnt figure out how to do damage to each enemy

1 Like

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