Good day, fellow developers,
After receiving some helpful feedback and giving it some thought, I’ve made some great improvements to the V3 Hitbox System! I’d love to hear your feedback and bug reports, so please feel free to share them.
Let me start by explaining the changes I’ve made to the way you input data. I’ve simplified it quite a bit. Now, all you need to provide is the Offset (which uses the HumanoidRootPart as the reference point), the Size, and the function that handles the Target and the Attacker. What’s notable is that this version no longer relies on parts as hitboxes. If you’re curious about what the new hitboxes look like, just keep reading for more info.
local Input = {}
Input['M1'] = {
Offset = CFrame.new(0,0,-2.5),
Size = Vector3.new(5,5,5),
Function = function(Target, Attacker)
Target:FindFirstChild('Humanoid'):TakeDamage(2.5)
print(Attacker.Name..' damaged '..Target.Name)
task.wait(1)
end,
}
return Input
Now, let’s talk about Object-Oriented Programming (OOP). I’ve made some adjustments to give you more control over when the hitbox is active or not. If you want the HitBox to stay visible, just use “true” when calling the StartDetection method .
local HitboxModule = {}
HitboxModule.__index = HitboxModule
local ActiveHitboxes = require(script.ActiveHitboxes)
local Input = require(script.Input)
function HitboxModule.new(Player, Type)
if ActiveHitboxes[Player] then return warn('Player is already running a hitbox!') end
local self = setmetatable({}, HitboxModule)
self.Player = Player
self.Type = Type
self.Hitbox = nil
self.InDetection = false
return self
end
function HitboxModule:StartDetection(Bool)
if self.InDetection then return warn('Already has been ranned!') end
self.InDetection = true
local Character = self.Player.Character or self.Player.CharacterAdded:Wait()
local HRP = Character:WaitForChild('HumanoidRootPart')
local Settings = Input[self.Type]
local OP = OverlapParams.new()
OP.FilterDescendantsInstances = {Character}
OP.FilterType = Enum.RaycastFilterType.Exclude
ActiveHitboxes[self.Player] = {Settings['Offset'], Settings['Size'], OP, Settings['Function'], self}
if Bool == true then
local Character = self.Player.Character or self.Player.CharacterAdded:Wait()
local HRP = Character:WaitForChild('HumanoidRootPart')
local Settings = Input[self.Type]
local Weld = Instance.new('WeldConstraint', HRP)
local HitPart = Instance.new('Part', HRP)
HitPart.Size = Settings['Size']
HitPart.CFrame = HRP.CFrame * Settings['Offset']
HitPart.Anchored = false
HitPart.CanCollide = false
HitPart.Massless = true
HitPart.Transparency = .75
HitPart.Color = Color3.fromRGB(255,0,0)
Weld.Part0 = HitPart
Weld.Part1 = HRP
self.Hitbox = {HitPart, Weld}
end
end
function HitboxModule:StopDetection()
if not self.InDetection then return warn('Already has been stopped!') end
if not ActiveHitboxes[self.Player] then return end
ActiveHitboxes[self.Player] = nil
self.InDetection = false
if self.Hitbox == nil then return end
for _, obj in self.Hitbox do
obj:Destroy()
end
end
function HitboxModule:Disconnect(Bool)
if Bool then
self:StopDetection()
end
if self.InDetection then return warn('Stop Detection First!') end
setmetatable(self, nil)
self = nil
end
return HitboxModule
Moving on to the main script that handles hitbox detection. I’ve added a separate dictionary for each player when they join the game. This helps manage their individual detection models. These player-specific dictionaries are removed either when the detection is complete or when a player leaves, which helps keep your game running smoothly. Plus, I’ve simplified things by using a single RunService Loop to handle all hitbox detections, which makes things faster .
local RS = game:GetService('ReplicatedStorage')
local ActiveHitboxes = require(RS.HitboxV3.ActiveHitboxes)
local YieldModels = {}
local Models = {}
game.Players.PlayerAdded:Connect(function(Player)
YieldModels[Player] = {}
Models[Player] = {}
end)
game.Players.PlayerRemoving:Connect(function(Player)
YieldModels[Player] = nil
Models[Player] = nil
if ActiveHitboxes[Player] then
local Hitbox = ActiveHitboxes[Player][5]
Hitbox:Disconnect(true)
ActiveHitboxes[Player] = nil
warn(Player.Name..' left during detection. Cleaned up!')
end
end)
game:GetService('RunService').Heartbeat:Connect(function()
for Player, Settings in ActiveHitboxes do
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild('Humanoid')
local HRP = Character:WaitForChild('HumanoidRootPart')
if Humanoid:GetState() == Enum.HumanoidStateType.Dead then return end
local Detection = game.Workspace:GetPartBoundsInBox(HRP.CFrame * Settings[1], Settings[2], Settings[3])
if #Detection == 0 then return end
for _, obj in Detection do
local Model = obj.Parent
if Models[Player][Model] then continue end
local Humanoid = Model:FindFirstChild('Humanoid')
if not Humanoid or not Model:IsA('Model') then continue end
if Humanoid:GetState() == Enum.HumanoidStateType.Dead then return end
Models[Player][obj.Parent] = obj.Parent
end
for _, Model in Models[Player] do
task.spawn(function()
if YieldModels[Player][Model] then return end
YieldModels[Player][Model] = Model
Settings[4](Model, Character)
if YieldModels[Player] then
YieldModels[Player][Model] = nil
end
if Models[Player] then
Models[Player][Model] = nil
end
end)
end
end
end)
To use this system, start by checking if the required input settings exist . It’s important to ensure that hitbox exists because this version only supports one at a time. You can easily turn the hitbox on and off using the StartDetection() and StopDetection() methods. Don’t forget to use the Disconnect() method when you’re done to free up memory .
local RS = game:GetService('ReplicatedStorage')
local HitboxV3 = require(RS.HitboxV3)
local Settings = require(RS.HitboxV3.Input)
local InputRemote = RS.InputRemote
InputRemote.OnServerEvent:Connect(function(Player, Type)
if not Settings[Type] then return end
if Type == 'M1' then
local Hitbox = HitboxV3.new(Player, Type)
if not Hitbox then return end
Hitbox:StartDetection(true)
task.wait(5)
Hitbox:StopDetection()
Hitbox:Disconnect()
end
end)
Your support and feedback are greatly appreciated!