Punch Event working long after it's fired

I was trying to replicate a simple punch/combat script which just plays an animation and sound and then damages any player that was touched by the arm of the player punching. The script doesn’t really work as intended because once you punch once, you can forever damage any player by just touching
them. Ill provide some gifs as an example below:

Any help is much appreciated :slightly_smiling_face:

https://gyazo.com/a83723c327e72200d12c1ddb38a2cf35

StarterPlayer Script:

local Player = game.Players.LocalPlayer

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventsFolder = ReplicatedStorage.Events

local CombatEvent = EventsFolder.Combat


Mouse = Player:GetMouse()

Mouse.Button1Down:Connect(function()
	CombatEvent:FireServer("Punch")
end)

Punch Event Script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventsFolder = ReplicatedStorage.Events
local SFXFolder = ReplicatedStorage.SFX
local AnimationsFolder = ReplicatedStorage.Animations

local PunchConnect = SFXFolder.PunchConnect
local PunchSwing = SFXFolder.Swing
local PunchAnimation = AnimationsFolder.Punch

local PunchEvent = EventsFolder.Combat

local CanPunch = true
local CoolDown = 0.3



PunchEvent.OnServerEvent:Connect(function(Player, Action, Target)
	
	local AnimationTrack = Player.Character.Humanoid:LoadAnimation(PunchAnimation)
	
	if Action == "Punch" then
		if CanPunch == true then
			CanPunch = false
			
			AnimationTrack:Play()
			local SwingSound = PunchSwing:Clone()
			SwingSound.Parent = game.SoundService
			SwingSound:Play()
			wait(0.5)
			SwingSound:Destroy()
			
			Player.Character["Left Arm"].Touched:Connect(function(Hit)
				if CanPunch == true then
				if Hit.Name == "Head" or "HumanoidRootPart" or "Torso" or "Left Arm" or "Right Arm" or "Left Leg" or "Right Leg" then
						Hit.Parent.Humanoid:TakeDamage(1.5)
						
					local PunchConnectSound = PunchConnect:Clone()
					PunchConnectSound.Parent = game.SoundService
						PunchConnectSound:Play()
						
						CanPunch = false
						wait(CoolDown)
						CanPunch = true
						
					wait(0.5)
						PunchConnectSound:Destroy()
					end
					
				else 
					return nil
					
				end
			end)
			
			
			wait(CoolDown)
			CanPunch = true
		end
	end
	

end)

You should make it :Once instead of :Connect. Or, you can disconnect it.

1 Like

Partially works, the same thing happens only it doesn’t repeat the damage, it just damages it once. My goal is for the punch itself to do damage as so as it hits another player and if it doesnt hit then it will just return nil.

https://gyazo.com/c193dbfe13af2a02f6aa2378fab9c43d

Maybe you should make the .Touched event on the client and then send over the hit players to the server?

1 Like

Use a connection for the .Touched function and Disconnect if the punch hits somebody because there is a new .Touched function creating everytime the event is fired (to my knowledge). Also, it seems like the animation is punching using the Right Arm and the code currently damages the players using the Left Arm.

Maybe try this:

local connection
connection = Player.Character["Right Arm"].Touched:Connect(function(Hit)
				if CanPunch == true then
				if Hit.Name == "Head" or "HumanoidRootPart" or "Torso" or "Left Arm" or "Right Arm" or "Left Leg" or "Right Leg" then
                   connection:Disconnect()
						Hit.Parent.Humanoid:TakeDamage(1.5)
						
					local PunchConnectSound = PunchConnect:Clone()
					PunchConnectSound.Parent = game.SoundService
						PunchConnectSound:Play()
						
						CanPunch = false
						wait(CoolDown)
						CanPunch = true
						
					wait(0.5)
						PunchConnectSound:Destroy()
					end
					
				else 
					return nil
					
				end
			end)

I would also put the .Touched function before the wait(0.5) because the script won’t detect anything until after the animation is done.

Same thing is happening unfortuantely. I think my best bet is to just fire the touched event on the client.

https://gyazo.com/93c0c5b69e146be056e5226689f11c71

You are never disconnecting the event, so the event will continue to be listened to. (And everytime you punch, you will keep adding more listeners, so eventually you can hit people 100 times a second!)

What you need to do is disconnect the event after the punch is over. (Like at the cooldown, maybe).

local punchListener
punchListener = Player.Character["Right Arm"].Touched:Connect(function(Hit) 
       -- Do stuff
end)

-- Wait until punch ends
punchListener:Disconnect()

Having the touched event client-side vs server-side should not be an issue at all.

1 Like

I used your solution and while it does solve the problem of not adding more listeners, the damage does not take place for some reason, no errors are being output. I do greatly appreciate the help thank you.

Code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventsFolder = ReplicatedStorage.Events
local SFXFolder = ReplicatedStorage.SFX
local AnimationsFolder = ReplicatedStorage.Animations

local PunchConnect = SFXFolder.PunchConnect
local PunchSwing = SFXFolder.Swing
local PunchAnimation = AnimationsFolder.Punch

local PunchEvent = EventsFolder.Combat

local CanPunch = true
local CoolDown = 0.3



PunchEvent.OnServerEvent:Connect(function(Player, Action, Target)

	local AnimationTrack = Player.Character.Humanoid:LoadAnimation(PunchAnimation)

	if Action == "Punch" then
		if CanPunch == true then
			CanPunch = false

			AnimationTrack:Play()
			local SwingSound = PunchSwing:Clone()
			SwingSound.Parent = game.SoundService
			SwingSound:Play()
			wait(0.5)
			SwingSound:Destroy()

			local punchListener
			punchListener = Player.Character["Right Arm"].Touched:Connect(function(Hit) 
					if Hit.Name == "Head" or "HumanoidRootPart" or "Torso" or "Left Arm" or "Right Arm" or "Left Leg" or "Right Leg" then
						Hit.Parent.Humanoid:TakeDamage(1.5)
						local PunchConnectSound = PunchConnect:Clone()
						PunchConnectSound.Parent = game.SoundService
						PunchConnectSound:Play()
						CanPunch = false
						wait(CoolDown)
						CanPunch = true
						wait(0.5)
						PunchConnectSound:Destroy()
					else
						return nil
					
				
				end
			end)

			-- Wait until punch ends
			punchListener:Disconnect()


			wait(CoolDown)
			CanPunch = true
		end
	end


end)

https://gyazo.com/7f57c557b045ba73e4624fab536eb06c

That’s because you are disconnecting the listener immediately after assigning it. Apologies, when I wrote the comment “Wait until punch ends”, I meant that you should put a yield of some sort there, or even put the disconnection in another event.

-- Wait until punch ends
task.wait(CoolDown)
CanPunch = true
punchListener:Disconnect()

Try putting it after the cooldown. I also recommend using task.wait() since it does not throttle and can do smaller numbers (wait() can take way longer than the number you put in!)

1 Like

Gotcha, that makes sense. Unfortuantely I am still going through difficulties with the punch. When dealing damage you are able to rapidly spam it but when you aren’t dealing damage then you are unable to spam it.

https://gyazo.com/318f92f14f6dd14bb19f5357c18fccda
https://gyazo.com/43731baafb28cf61a08453418025675c

Code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventsFolder = ReplicatedStorage.Events
local SFXFolder = ReplicatedStorage.SFX
local AnimationsFolder = ReplicatedStorage.Animations

local PunchConnect = SFXFolder.PunchConnect
local PunchSwing = SFXFolder.Swing
local PunchAnimation = AnimationsFolder.Punch

local PunchEvent = EventsFolder.Combat

local CanPunch = true
local CoolDown = 0.3



PunchEvent.OnServerEvent:Connect(function(Player, Action, Target)

	local AnimationTrack = Player.Character.Humanoid:LoadAnimation(PunchAnimation)

	if Action == "Punch" then
		if CanPunch == true then
			CanPunch = false

			AnimationTrack:Play()
			local SwingSound = PunchSwing:Clone()
			SwingSound.Parent = game.SoundService
			SwingSound:Play()
			wait(0.5)
			SwingSound:Destroy()

			local punchListener
			punchListener = Player.Character["Right Arm"].Touched:Connect(function(Hit) 
					if Hit.Name == "Head" or "HumanoidRootPart" or "Torso" or "Left Arm" or "Right Arm" or "Left Leg" or "Right Leg" then
						Hit.Parent.Humanoid:TakeDamage(1.5)
						local PunchConnectSound = PunchConnect:Clone()
						PunchConnectSound.Parent = game.SoundService
						PunchConnectSound:Play()
						CanPunch = false
					task.wait(CoolDown)
					CanPunch = true
					punchListener:Disconnect()
						wait(0.5)
						PunchConnectSound:Destroy()
					else
						return nil
					
				
				end
			end)

			


			task.wait(CoolDown)
			CanPunch = true
		end
	end


end)

I think there’s an inherent issue in the event logic. Try using these changes:

            local hitHumanoids = {} -- Store a dictionary of all humanoids hit
			local punchListener
			punchListener = Player.Character["Right Arm"].Touched:Connect(function(Hit) 
				if Hit.Name == "Head" or "HumanoidRootPart" or "Torso" or "Left Arm" or "Right Arm" or "Left Leg" or "Right Leg" then
					-- You only want to hit each person once
					if hitHumanoids[hit.Parent] then return end
					hitHumanoids[hit.Parent] = true
					
					Hit.Parent.Humanoid:TakeDamage(1.5)
					
					local PunchConnectSound = PunchConnect:Clone()
					PunchConnectSound.Parent = game.SoundService
					PunchConnectSound:Play()
					task.wait(0.5)
					PunchConnectSound:Destroy()
				end
			end)

			task.wait(CoolDown)
			CanPunch = true
			punchListener:Disconnect()

You’re setting your debounce and having cooldowns multiple times throughout your event, which is probably not what you want. Also, since you must detect collisions throughout the entirety of the punch animation, you need to keep a list of all the humanoids you have punched - so you only punch them at most 1 time.

1 Like

That makes a lot of sense, I was wondering if having 2 cooldowns could be an issue. Thanks for the help and your time I really appreciate it. :slightly_smiling_face:

1 Like

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