Welcome to my tutorial on programming a sword that does damage when you swing it! You will also learn how to make a custom hitbox and how to prevent getting multiple hits on the same person.
Part A - Preparing the sword
The first step is to choose a sword model. I used the basic Roblox sword model. In the explorer window, your sword should look similar to this. It needs to be a tool with a handle; in this case, the handle is the part with the mesh. However, a mesh is not required
Now you can create the hitbox. Do this by inserting a part under the sword tool and naming it Hitbox, then putting it where you want the hitbox to be. Make sure it has can-touch on and can-collide off and use a weldConstraint to connect it to the rest of your sword. To create a weldConstraint, add it as an object to your Handle. Then in properties, set part1 to the handle, and part2 to the hitbox. The hitbox can be made transparent too.
The next step is to create animations. One will need to be made for both r6 and r15. First, create a rig using the rig builder in the avatar tab. Then place the sword tool in it like this:
Next, use the animation editor in the avatar tab to create and save a sword swing animation for r6 and r15. As this is a scripting tutorial, it won’t go into how to create animations, but many resources are available. Ensure their AnimationPriority is Action. Once you have your animations, create animation objects inside the sword tool and input the IDs in their properties.
Part B - Scripting the sword
To start, create a local script and a remote event called SwordSwingEvent as direct children of your sword. I’ll provide the code, which has comments in it if you are unsure what something does. This code is for the local script:
local sword = script.Parent -- Creates a variable that is the sword
local swingOnCooldown = false -- Creates a variable that is the cooldown for the sword
local SwordSwingEvent = sword.SwordSwingEvent -- Remote event to communicate with the server
local function swing() -- This function runs whenever the sword is activated
if swingOnCooldown == false then -- If the sword isn't on cooldown
swingOnCooldown = true -- Set it to be on cooldown
local humanoid = sword.Parent:FindFirstChild("Humanoid") -- Find the player's humanoid
local animator = humanoid:FindFirstChildOfClass("Animator") -- Find the player's animator
local swingAnimation -- Create empty swingAnimation variable for later use
if humanoid.RigType == Enum.HumanoidRigType.R6 then -- If the player is r6
swingAnimation = sword:FindFirstChild("r6Animation") -- Use the r6 animation
elseif humanoid.RigType == Enum.HumanoidRigType.R15 then -- If the player is r15
swingAnimation = sword:FindFirstChild("r15Animation") -- Use the r15 animation
end
local SwingTrack = animator:LoadAnimation(swingAnimation) -- Load the swing animation into the player's animator
SwingTrack:Play() -- Play the animation
SwordSwingEvent:FireServer() -- Fires remote event to server script
end
wait(1) -- Wait 1 second
swingOnCooldown = false -- Allow the player to swing again
end
sword.Activated:Connect(swing) -- Runs swing function when the player clicks while holding the tool
Next, add a server script under your sword tool. This is the server code, once again with comments.
local sword = script.Parent -- Creates a variable that is the sword
local hitbox = sword.Hitbox -- Creates a variable that is the hitbox
local SwordSwingEvent = sword.SwordSwingEvent -- Remote event to get a message from the client
local recentlyHit = {} -- Create array for recently hit targets
local function checkHumanoid(humanoid) -- Function to check if a specific humanoid is in the recently hit list
if #recentlyHit == 0 then -- If nobody has been recently hit
return false -- provides false value
end
for _, recentHumanoid in ipairs(recentlyHit) do -- Campare all values in the array to the humanoid
if recentHumanoid == humanoid then -- If the humanoid appears on the array list
return true -- provides true value
end
end
return false -- In any other case provide false
end
local function doDamage(objectHit) -- Function to handle the damage triggered by hitbox getting touched
local humanoid = objectHit.Parent:FindFirstChild("Humanoid") -- Look for humanoid
if humanoid and checkHumanoid(humanoid) == false then -- If it has a humanoid and it's not been hit recently
table.insert(recentlyHit, humanoid) -- Add it to recently hit array
humanoid:TakeDamage(10) -- have humanoid take damage
end
end
SwordSwingEvent.OnServerEvent:Connect(function() -- When server event is triggered
local connection -- Create variable to hold the connection
connection = hitbox.Touched:Connect(doDamage) -- turn on the connection to damage function
wait(1) -- Wait 1 second
connection:Disconnect() -- turn off the connection to damage
recentlyHit = {} -- Empty the recently hit array
end)
Congratulations, you created a sword with a custom hitbox that hits each enemy only once per swing. Now all you have to do is place the sword in StarterPack to spawn with it. You can test it out by placing some rigs. Additionally, this link is to an uncopylocked version of the game: Sword Tutorial - Uncopylocked - Roblox. Hopefully, you found this tutorial helpful and if you need help, feel free to leave a comment!