I have three issues that I need answers for that involve my "Punching Script."

Hey everyone, sorry for the long post. I am in need of help because this is actually my first time scripting and I could use some guidance. If you have any knowledge of the solution to these following questions, please let me know in the comment section! :slightly_smiling_face:

1. I was writing a punching script and I came across an issue where if I pressed the Keybind “f” more than once it would cancel the animation if it had not finished from the first time I pressed the button and I would start the animation over. Basically, I am trying to figure out how I can implement an interval or a “reload time” in between each punch to prevent spamming and other issues.**

2. I want to change the Keybind to the Left Mouse Button but I am not sure how.

3. How can I make it so the animation can vary? I have two animations, a right hand punch and a left hand punch. I want to know how I can make it so that the animations will alternate for each punch.
:arrow_down:
For example: First click would be a right hand punch and then the second click would be a right hand punch.

Here is a screenshot of my script:

1 Like

You should copy and paste your script instead of just sending a screenshot, so that we can read it easier.

Alright here ya go;

CanDoDmg = true
Keybind = "RightMouseButton"
dmg = 10


local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()

mouse.KeyDown:Connect(function(key)
	if key == Keybind then
		local anim = script.Parent.Humanoid:LoadAnimation(script.Animation)
		anim:Play()
		script.Parent.RightArm.Touched:connect(function(hit)
			if hit.Parent.Humanoid and CanDoDmg == true then
			hit.Parent.Humanoid:TakeDamage(dmg)
			CanDoDmg = false
			wait(1)	
			CanDoDmg = true
			end
		end)
	end
end)

Please use this syntax:
“```lua”

It makes us easier to read like what @Uzixt said to you.

1 Like

Thanks for that lol. I was not sure how to get it into the lua format. :sweat_smile: I am such a rookie.

1 Like

Don’t use the .Touched event that way, either use it out of the KeyDown event or use part:GetTouchingParts().

And I believe you should be using Mouse.Button1Down instead of Mouse.KeyDown, as I don’t think that’s even an event

For number 1, add a variable named something like “punching” to act as a flag to tell if you are already punching. If the player inputs a punch, check if “punching” is true, and if it isn’t, set it to true and let the player punch. Then, use the AnimationTrack’s stopped event to reset that flag once the animation ends.

For number 2, use the UserInputService’s InputBegan event.

For number 3, you can use another variable to keep track of the last hand used to punch, let’s call it “rightHandPunched”. It’ll default to false, and every time you punch, it flips from false to true or vise versa. If it’s false when the player punches, play the right hand punch animation and flip it to true. If it’s true when the player punches, do the left hand punch animation instead.

Put all these together and we might get something like this:

CanDoDmg = true
dmg = 10

local userInput = game:GetService("UserInputService")
local plr = game.Players.LocalPlayer
local punching = false
local rightHandPunched = false
userInput.InputBegan:Connect(function(key)
	if key ==Enum.UserInputType.MouseButton1 and not punching then
                punching = true
                local anim;
                local touchEvent;
                if not rightHandPunched then
		    anim = script.Parent.Humanoid:LoadAnimation(script.RightHandPunch) --there must be an animation named RightHandPunch under the script for this to work.
                    touchEvent = script.Parent.RightArm.Touched:connect(function(hit)
			if hit.Parent.Humanoid and CanDoDmg == true then
			    hit.Parent.Humanoid:TakeDamage(dmg)
			    CanDoDmg = false
			    wait(1)	
			    CanDoDmg = true
			end
		    end)
                else
		   local anim = script.Parent.Humanoid:LoadAnimation(script.LeftHandPunch) --there must be an animation named LeftHandPunch under the script for this to work.
                   touchEvent = script.Parent.LeftArm.Touched:connect(function(hit)
 		        if hit.Parent.Humanoid and CanDoDmg == true then
			    hit.Parent.Humanoid:TakeDamage(dmg)
			    CanDoDmg = false
			    wait(1)	
   			    CanDoDmg = true
			end
		    end)
                end
                
 		anim:Play()
		
               animationTrack.Stopped:wait()
               touchEvent:Disconnect();
              punching = false;
              rightHandPunched = not rightHandPunched;
	end
end)

A quick note: I also stored the Touched event in a variable so we can disconnect from the event once the animation ends. The reason why we do this is because if we don’t disconnect a function we connect to an event, it will continuously listen to the event and run the code inside whenever the event fires. In this case, if we don’t disconnect from the Touched event the player could potentially still hurt other players with their arm even if they aren’t in the punching animation.

2 Likes

Thanks man, I appreciate it. However, I don’t fully understand all of this because this is legit the first time I have coded in Lua so I have no clue. Although, I have the anims but the script itself did not work and I can’t figure out why.

1 Like

No, Don’t make it all client sided.

--// LocalScript
local Keybind = "RightMouseButton";
local Debounce = false; --// For animation

local Remote = game:GetService("ReplicatedStorage"):WaitForChild("PunchEvent");


local plr = game:GetService("Players").LocalPlayer;
local mouse = plr:GetMouse();

--// For right click change the 1 to a 2
mouse.Button1Down:Connect(function()
	if not Debounce then
		Debounce = true;
		local anim = script.Parent.Humanoid:LoadAnimation(script.Animation);
		anim:Play();
		Remote:FireServer();
		wait(1) --// Time before you can use punch again.
		Debounce = false;
	end
end)
--// Server Script
local Remote = Instance.new("RemoteEvent", game:GetService("ReplicatedStorage"));
Remote.Name = "PunchEvent";

local serverDebounce = {};
local dmg = 10;

Remote.OnServerEvent:connect(function(player)
	local Character = player.Character;
	if Character and Character:FindFirstChild("Humanoid") and not serverDebounce[player] then
		local Humanoid = Character.Humanoid;
		local PeopleGettingHit = Character.RightArm:GetTouchedParts();
		for _,v in pairs(PeopleGettingHit) do
			if v.Parent:FindFirstChild("Humanoid") then
				v.Parent.Humanoid:TakeDamage(dmg);
				break;
			end
		end
		serverDebounce[player] = true;
		wait(1) --// Time to wait before calling it again (preventing exploiters)
		serverDebounce[player] = nil;
	end
end)
3 Likes

Is it the script giving any errors or is it just not working?
If it’s just not working, I realized when looking at it again that

hit.Parent.Humanoid:TakeDamage(dmg)

will not work in a LocalScript. If a player wants to do damage to another player, it has to ask the server to do so using a RemoteEvent.
You can replace that line with something like

game:GetService("ReplicatedStorage"):FindFirstChild("DamagePlayer"):FireServer(hit.Parent.Humanoid);
--create a RemoteEvent in the root of ReplicatedStorage named DamagePlayer for this to work

and then in a Script located inside of ServerScriptService have something like this inside:

local function DamagePlayer(requestingPlayer,targetHumanoid)--remote events fired from a client always provide the player that fired it as the first argument.
   local dmg = 10;
   targetHumanoid:TakeDamage(dmg)
end
game:GetService("ReplicatedStorage"):FindFirstChild("DamagePlayer").OnServerEvent:Connect(DamagePlayer)

Keep in mind that this is a very simple example, and would be very easy for exploiters to use to cheat. You could guard against this by doing some checks in the DamagePlayer function in the Script such as checking that the requestingPlayer’s character is close enough to the targetHumanoid’s parent in order to do damage. Here is a short article with some basic info on this.

1 Like

This is far more vulnerible to what I suggested.

an exploiter could just do this:

for _,player in pairs(game.Players:GetPlayers) do
    local char = player.Character;
    game.ReplicatedStorage.DamagePlayer:FireServer(char.Humanoid);
end

killing everyone within the game.

Yes it is, which is why I mentioned as much at the end of my post. It’s not meant to be a permanent solution, just something simple to get the script to work for now.