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:
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)
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.
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)
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.
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)
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!)
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.
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.