Hello,
This is my first post so correct me if I’m doing something wrong.
I have a punch tool, which you can use to damage and kill players. The tool works fine for me in game and in studio, however when someone else except me uses the tool, the touched event doesn’t seem to work. I have got no idea why. The code is below, “Handtouched” and “Hit” isn’t printing for all players, except me. The rest prints. This is a normal script and a child of the tool (starterpack).
local tool = script.Parent
local waitTime = 1 -- set this to the time between each damagehit
local damageAmount = 10 -- set this to the amount of damage each damagehit does
local canDamage = tool.CanDamage
local clickGoing = false
local TouchConnection -- touch event for the right hand
local TouchConnectionLeft -- touch event for the left hand
print(canDamage)
local player = tool.Parent.Parent
print (player.Name)
local character = player.Character
if not character or not character.Parent then -- check if character loaded
character = player.CharacterAdded:wait()
end
local RightHand = character:WaitForChild("RightHand")
local LeftHand = character:WaitForChild("LeftHand")
local function HandTouched(hit)
print("Handtouched")
print(canDamage.Value)
if hit.Parent:FindFirstChild("Humanoid") and canDamage.Value == true then
print("hit")
canDamage.Value = false
local humanoid = hit.Parent.Humanoid
humanoid.Health = humanoid.Health - damageAmount
end
end
tool.Activated:Connect(function()
if clickGoing == false then
print (player.Name)
print(RightHand.Name)
print(LeftHand.Name)
TouchConnection = RightHand.Touched:Connect(HandTouched)
TouchConnectionLeft = LeftHand.Touched:Connect(HandTouched)
print("epic")
if clickGoing == false then
clickGoing = true
wait(waitTime)
TouchConnection:Disconnect()
TouchConnectionLeft:Disconnect()
canDamage.Value = true
clickGoing = false
print("You can damage again")
end
end
end)
When you say that the HandTouched function isn’t working for other players, do you mean that when you do it, they can’t see it happening and “Handtouched” only prints for you? Or do you mean that if they have the tool, they can’t use it?
They see the animation work (Which is in a localscript), but they don’t do any damage. In the server output I only see “Handtouched” print when I click, not when other players click.
It makes sense that you don’t see “Handtouched” printed when others use it because it is in a local function. Try removing local from the function HandTouched(hit).
Animations are replicated to all other clients, which is why they can see the animation. However, in regards to damage, if you’re doing this in a LocalScript this will not replicate to other clients, as this is where FilteringEnabled comes into play.
You’re going to want to look into RemoteEvents which will allow a client to ‘tell the server’ to do something by using :FireServer() on that RemoteEvent, and on the server you’ll have code that will run .OnServerEvent on that RemoteEvent. Obviously, you’ll want to ensure there are some server side checks to make sure the player is allowed to actually damage the character instead of straight up damaging them as that can prove to be exploitable otherwise.
This damage script, which checks if the hand touches a player, is not a local script but a server side script. Only the animation is in a separate local script.
When you say it doesn’t work for other players, how are you testing that? Can you explain the way you are testing the multiplayer functionality? It might help in solving this.
I’m not exactly sure what is wrong with your script, but I would suggest against using .Touched events to deal damage from an attack. I’ve tried using that event before for melee attacks, and it seems to be very unreliable at actually detecting touching parts.
What I would do is:
Have a LocalScript specifically handle detection
In this script, use Raycasting to fire a ray to where your fist or weapon is going
Cast this ray on every frame the client sees, using game:GetService("RunService").Heartbeat, or any of the other similar events
Send anything the rays hit to a normal Script
Sanity check the hits; make sure the attacker didn’t punch someone from 100 studs away
Have the serverscript disable/enable this localscript when you want to get input, and be sure to only use data from the client when the server has the localscript enabled.
Having a localscript handle hitboxes has some good and bad aspects, though I would definitely say the pros outweight the cons. For one, since you are getting hitboxes from the client, this is exploitable. Someone could spoof what they hit to the server. This means you should do that sanity check I mentioned as step #5, however this means that there is no way to be 100% secure. On the bright side, the user attacking will always deal damage if they see their hit connect, and firing a ray for each frame has proven to be an extremely accurate method for me. Depending on your level of scripting experience, this might be a bit too advanced for you, but if you’re up for it, I would highly suggest using this method for melee-ish attacks.
I am just testing it in game, by joining a server with other players. When they hit me, they don’t deal any damage and “Handtouched” and “Hit” do not appear in the server output. When I hit them then I deal damage and “Handtouched” and “Hit” are printing in the server output.
If you are sticking with your script that you’ve made, here are some changes you need to/should do:
There is a print(canDamage), make sure you change that to print(canDamage.Value), otherwise it will be printing an object and not a value
Get rid of the second if clickGoing == false then, since it is redundant. This isn’t a bad thing though, just useless to do seeing as you already check it beforehand.
You are setting canDamage to true AFTER you have disconnected the .Touched events to HandTouched. That may be the big issue that you are looking to solve. Move that line before the disconnecting and waiting.
Here’s your code, revised a bit and with the changes I mentioned above. I am not available at the moment to test this in studio, so I can’t say this will 100% work, but I’m pretty sure this’ll do.
local tool = script.Parent
local waitTime = 1
local damageAmount = 10
local canDamage = tool.CanDamage
local clickGoing = false
local TouchConnectionRight --Adding RIGHT to be more specific
local TouchConnectionLeft
print(canDamage.Value) --Be sure to use .VALUE for these, otherwise you're printing an object and not a value
local player = tool.Parent.Parent
print (player.Name)
local character = player.Character or player.CharacterAdded:Wait() --You can do this with one line
local RightHand = character:WaitForChild("RightHand")
local LeftHand = character:WaitForChild("LeftHand")
local function HandTouched(hit)
print("Handtouched")
print(canDamage.Value)
if canDamage.Value then --Since canDamage.Value is either true or false, you don't have to use .Value in an IF statement. If canDamage is true, then it passes through the IF.
-- I would suggest creating variables for the stuff you need when attacking someone
local model = hit:FindFirstAncestorOfClass("Model") --This will try to get whatever "model" hit is under. If there is no model, then it will be nil
local human
if model then --If hit is part of a model...
human = model:FindFirstChildOfClass("Humanoid") -- This will try to get a 'humanoid' instance directly under 'model'. If there is none, it will return nil
end
if human then --Check to see if a humanoid was found
print("Hit a humanoid")
human:TakeDamage(damageAmount) --I would suggest using TakeDamage instead of subtracting health, since TakeDamage understands what forcefields are, and won't hurt players that have just spawned.
canDamage.Value = false
end
end
end
tool.Activated:Connect(function()
if clickGoing == false then --You can also write it as "if not clickGoing then"
clickGoing = true
canDamage.Value = true
TouchConnectionRight = RightHand.Touched:Connect(HandTouched)
TouchConnectionLeft = LeftHand.Touched:Connect(HandTouched)
wait(waitTime)
canDamage.Value = false --Adding this to make sure canDamage gets set to false, even if the player misses and doesn't hit anything
TouchConnectionRight:Disconnect()
TouchConnectionLeft:Disconnect()
clickGoing = false
print("You can damage again")
end
end)
This script is better setted up, thank you, but it’s still not working for other players. Only player.Name, canDamage.Value and “You can damage again” are printing. When I hit a player then it works, but still not for others.