There aren’t many hitbox resources not made for projectiles that are easy to use right out of the box, even if they offload checks to the client they often do not include basic authentication to prevent exploiting. This is why I recommend you use my hitbox module, it authenticates to prevent exploiting and accommodates for latency (lagging players) and velocity dynamically. Its easy to use and requires no additional authentication checks right away.
This resource fixes character latency by offloading to clients without network latency interfering. Offload hitboxes to clients whenever the hitbox position changes relative to the character’s position i.e. welding a hitbox to the character.
Here is a showcase using it in my own game.
STEP 1: DOWNLOAD
Download the module here!
STEP 2: SETUP
Place the module in ReplicatedStorage and require it on both the server and client.
-- Example
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Hitbox = require(ReplicatedStorage:WaitForChild("Hitbox")
STEP 3: GET YOUR PART
Locate the part you want to create a hitbox with, OR create one using the .Part() method.
.Part(
Size: Vector3 | number, -- If Vector3 then returns Block, if number then returns Sphere
WeldTo: BasePart?, -- Optionally weld the part to another part
Offset: CFrame? -- Optional offset for the weld
) -> Part -- Returns a part
-- Example
local Part = workspace.Part
-- OR
local Character = workspace.Player1 -- path to character
local Size = 5
local Part = Hitbox.Part(
Vector3.new(Size, Size, Size), -- Size: or use a number (the part will become a sphere)
Character.PrimaryPart, -- Weld To Part: Optional, welds the part to this part.
CFrame.new(0, -.5, ((Size / 2) * -1) -- Weld Offset: Optional, offsets the weld around another part.
)
STEP 4: CREATE A HITBOX
It is recommended that you do NOT create a new hitbox every time you use an ability. You should create one hitbox per ability when the ability script loads. The hitbox should be created long before it is used. It is also recommended that you offload hitboxes to the client if you intend for the hitbox to be moving with the character or when welding the hitbox to the character.
.New(
Focus: BasePart, -- The part you want the hitbox to use
Parameters: OverlapParams?, -- Overlap parameters for whitelist/blacklist
Client: Player?, -- Optional, offload the hitbox onto a client
Debug: boolean? -- Whether or not to show debug visuals in studio
) -> hitbox -- returns a hitbox
STEP 5: SETUP CONNECTIONS
Each hitbox comes with several events you can connect to.
To listen for characters being hit connect to the .Hit() event, this event will return a table of characters that get hit.
hitbox.Hit:Connect(function(characters: {Model})
-- Make sure to use a task.spawn() here so effects happen to all hit characters simultaneously.
end)
You can listen for characters entering or leaving the hitbox with the .TouchBegan() & .TouchEnded() events.
hitbox.TouchBegan:Connect(function(character: Model)
-- logic here
end)
hitbox.TouchEnded:Connect(function(character: Model)
-- logic here
end)
You can listen for the hitbox being started or stopped with the .Started() & .Stopped() events.
hitbox.Started:Connect(function()
-- logic here
end)
hitbox.Stopped:Connect(function()
-- logic here
end)
You can listen for the hitbox being destroyed with the .Destroying() method. You only need to connect to this once.
hitbox.Destroying:Once(function()
-- logic here
end)
STEP 6: CONTROL THE HITBOX
For one time hit detection, use the :Once() method. A table of characters that were hit will be returned. If no characters were hit an empty table is returned.
:Once() -> {Characters}
To activate the hitbox use the :Start() method and to stop it use the :Stop() method. Once a character has been hit it can no longer be hit. If you want the hitbox to automatically stop after a given duration then pass a number as the Timer: number? parameter. If you would like the hitbox to have reoccurring hits to the same character pass a number to the Debounce: number? parameter.
hitbox:Start(Timer: number?, Debounce: number?)
hitbox:Stop()
Hitboxes store characters so they cant be hit again. If you would like them to be hit again, use the :Clear() method. You should do this every time you plan on reusing the hitbox.
hitbox:Clear()
You can weld the hitbox to a part with an offset, or change the hitboxes current weld and offset, with the :Weld() method. This will return a weld instance.
hitbox:Weld(Part: BasePart, Offset: CFrame?) -> Weld
To see if the hitbox has been started, use the :IsActive() method. This will return a boolean.
hitbox:IsActive() -> boolean
Once you no longer need the hitbox, use the :Destroy() method to remove it from server memory. If the part a hitbox was made from gets destroyed the hitbox object is automatically destroyed too.
hitbox:Destroy()
EXAMPLE CODE
-- Example
local damage = 10
local debounce = .5
local duration = 3
local hitboxSize = Vector3.new(5, 5, 7)
local Character = game.Players.Player1.Character
local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {Character}
hitbox = Hitbox.New(
Hitbox.Part(hitboxSize, hrp, CFrame.new(0,-.5,((hitboxSize.Z / 2) * -1)) ),
params,
Players:GetPlayerFromCharacter(Character),
true
)
Character.Destroying:Once(function()
hitbox.Focus:Destroy()
hitbox:Destroy()
end)
hitbox.Hit:Connect(function(characters: {Model})
for _,character in pairs(characters) do
task.spawn(function()
local humanoid = character:FindFirstChildOfClass("Humanoid")
humanoid:TakeDamage(damage)
end)
end
end)
hitbox.TouchBegan:Connect(function(character: Model)
print(character.Name.." has entered the hitbox.")
end)
hitbox.TouchEnded:Connect(function(character: Model)
print(character.Name.." has left the hitbox.")
end)
hitbox.Started:Connect(function()
print("Hitbox started.")
end)
hitbox.Stopped:Connect(function()
print("Hitbox stopped.")
end)
hitbox.Destroying:Once(function()
print("Hitbox successfully destroyed.")
end)
-- Using the hitbox
hitbox:Clear()
hitbox:Start(duration, debounce)
-- OR
hitbox:Clear()
hitbox:Start(nil, debounce)
task.wait(duration)
hitbox:Stop()
If you have any question or feature requests, please let me know!