Hitbox Service, easily create Accurate Hitboxes using minimal scripting!

Are you tired of using .touched hitboxes, constantly not working? Well, Hitbox Service may be the module for you!
Download here: Hitbox Service - Roblox
As you can see, I made a hitbox which would damage the player

Source Code:

Source Code
-- biack1st
--[[
	HELLO!! thank you SO much for downloading this module!!! In order to use this module please look at the devforum post: 
]]--
local module = {}


local RunService = game:GetService("RunService")
module.__index = module
setmetatable({}, module)
---[HitBox Modules]-----
local CreateWithRegion = require(script.CreateWithRegion)
local CreateWithRange = require(script.CreateWithRange)
local CreateWithPart = require(script.GetPartsInPart)

function module:CreateWithRange(StartingPart:BasePart,StartingPos:Vector3, Range:number, Overlap_Params:OverlapParams)
	local Started = false
	Overlap_Params.FilterDescendantsInstances = {StartingPart, Overlap_Params.FilterDescendantsInstances}
	local HitboxCreated = CreateWithRange:Create(StartingPos, Range, Overlap_Params)
	function self:Start()
		Started = true
	end
	function self:GetItems()
		local Items = {}
		if Started == true then
		for i,v in pairs(HitboxCreated) do
			
				if table.find(CreateWithRange:Create(StartingPos, Range, Overlap_Params), v) and v ~= nil then
					table.insert(Items, v)
			
			end
			end
		else
			error("Cannot get items when hitbox hasn't started. To start do: hitbox:Start()")
			end
		return Items
	end
	function self:Stop()
		if Started == true then
			Started = false
		else
			error("Cannot stop a hitbox that hasn't started. To start do: hitbox:Start()")
		end
	end
	function self:GetState()
		return Started
	end
		
		return self

end

function module:CreateWithBox(StartingPart : BasePart, RegionCFrame : CFrame, RegionSize : Vector3, Overlap_Params : OverlapParams)
	local Started = false
	Overlap_Params.FilterDescendantsInstances = {StartingPart, Overlap_Params.FilterDescendantsInstances}
	local HitboxCreated = CreateWithRegion:Create(RegionCFrame, RegionSize, Overlap_Params)

	function self:Start()
		Started = true
	end

	local Event = script.Presets.EnteredEvent:Clone()
	self.Entered = Event.Event
	function self:GetItems()
	
		if Started == true then
			
		local Items = {}
		for i,v in pairs(HitboxCreated) do
				if table.find(CreateWithRegion:Create(RegionCFrame, RegionSize, Overlap_Params), v) and v ~= nil and Started == true then
				table.insert(Items, v)

			end
		end
			return Items
		else
			error("Cannot get items when hitbox hasn't started. To start do: hitbox:Start()")
		end
		
	end
	
	RunService.Heartbeat:Connect(function()
		local Items = self:GetItems()
		local NewHitbox = CreateWithRegion:Create(RegionCFrame, RegionSize, Overlap_Params)
		for i,v in pairs(NewHitbox) do
			if table.find(CreateWithRegion:Create(RegionCFrame, RegionSize, Overlap_Params), v) then
				Event:Fire(v)
			end
			
		end
	
		
	end)
	
	
			

		


	
	function self:Stop()
		if Started == true then
			Started = false
		else
			error("Cannot stop a hitbox that hasn't started. To start do: hitbox:Start()")
		end
	end
	function self:GetState()
		return Started
	end
		
		
	
	
	return self
end

function module:CreateWithPart(Part:BasePart, Overlap_Params:OverlapParams)
	local Started = false
	local Event = script.Presets.EnteredEvent:Clone()
	self.Entered = Event.Event
	Overlap_Params.FilterDescendantsInstances = {Part, Overlap_Params.FilterDescendantsInstances}
	local HitboxCreated = CreateWithPart:Create(Part, Overlap_Params)
	function self:GetState()
		return Started
	end
	function self:Start()
		Started = true
	end
	function self:GetItems()
		if Started == true then
			local Items = {}
			for i,v in pairs(HitboxCreated) do

				if table.find(CreateWithPart:Create(Part, Overlap_Params), v) and v ~= nil and Started == true then
					table.insert(Items, v)

				end
			end
			return Items
		else
			error("Cannot get items when hitbox hasn't started. To start do: hitbox:Start()")
		end
	
	end
	------[Presets]---------
	
	RunService.Heartbeat:Connect(function() --- entered preset
		if self:GetState() == true then
		local Items = self:GetItems()
		local NewHitbox = CreateWithPart:Create(Part, Overlap_Params)
		for i,v in pairs(NewHitbox) do
			if table.find(CreateWithPart:Create(Part, Overlap_Params), v) then
				Event:Fire(v)
				end
	
			end
		else
			error("Cannot use the preset entered without starting a hit box. To start the hit box do: hitbox:Start()")	
		end


	end)
	function self:Stop()
		if Started == true then
			Started = false
		else
			error("Cannot stop a hitbox that hasn't started. To start do: hitbox:Start()")
		end
	end

	return self
	
end



return module

How to set up:

How to set up:

First, you’ll need to download the module here
Next, open up the module by going to toolbox → inventory then insert the module into replicated storage.
After that, you’ll need to insert a script. Make sure to insert it in a part so we can make a hitbox!

Once you insert a script, Require the module!

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)

Now lets get into the juicy part, making the hitbox! Now, there are multiple methods to do this. In my opinion, :CreateWithPart is the easiest. All the other methods are similar to this method

In order to do :CreateWithPart, you’ll need a BasePart and overlap params. This is needed to do whitelists and black lists. By default, it’ll automatically filter through that part it was originally casted from. I don’t want it to filter through anything, so I’m going to keep it blank

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
local Params = OverlapParams.new()

Once you type that out, you’ll need to call the function. Make sure to make the function a VARIABLE. This is for the later steps so we can make it do what we want!

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
local Params = OverlapParams.new()
local Hitbox = HitboxModule:CreateWithPart(script.Parent, Params)

Now, we’re almost done. The next step is to tell the script to start using the hitbox! You can do this by doing: Hitbox:Start(). This is needed for the next step(making it do something DUH!)

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
local Params = OverlapParams.new()
local Hitbox = HitboxModule:CreateWithPart(script.Parent, Params)
Hitbox:Start()

Last but not least, making do what we want! This might feel complex, but trust me, it’s simple. Just follow along. We’ll first need to get the items that are currently in the hit box. To do this we can do: Hitbox:GetItems(). It’ll return a table that will say every item that’s currently in the hitbox. Make sure to make this a VARIABLE!

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
local Params = OverlapParams.new()
local Hitbox = HitboxModule:CreateWithPart(script.Parent, Params)
Hitbox:Start()
local Items = Hitbox:GetItems()

Next is doing stuff with the items. We’ll need to use a for loop to do this. You can make it do ANYTHING you want! But for me, I want it to print the item’s name.

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
local Params = OverlapParams.new()
local Hitbox = HitboxModule:CreateWithPart(script.Parent, Params)
Hitbox:Start()
local Items = Hitbox:GetItems()
for i,Object in pairs(Items) do -- loops through the items that are currently in the hitbox
	if Object:IsA("BasePart") then -- make sure it's a part!
	print(Object.Name) -- prints the name of the object
	end
end

Making it repeat
This will ONLY calculate ONCE! Which isn’t what we want. We’ll need to use RunSerivce.HeartBeat:Connect(function() in order to make it re-calculate.

local RunService = game:GetService("RunService") -- gets run service
local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
RunService.Heartbeat:Connect(function()
	local Params = OverlapParams.new()
	local Hitbox = HitboxModule:CreateWithPart(script.Parent, Params)
	Hitbox:Start()
	local Items = Hitbox:GetItems()
	for i,Object in pairs(Items) do -- loops through the items that are currently in the hitbox
		if Object:IsA("BasePart") then -- make sure it's a part!
			print(Object.Name) -- prints the name of the object
		end
	end
end)

That’s it! Now it’ll print the name of the object thats inside of the hit box! Keep in mind, you can use this to make ANYTHING you want! Printing the object’s name was a simple example.

Why should I use this compared to other methods?

Why should I use this compared to other methods?

Touch Events: The main reason why you should, under ANY circumstance NOT use this is because it isn’t that good at detecting things. For example. Touch events have TONS of issues, server delay and much more. So using this for a hit box isn’t the best idea

Ray Casting Hit boxes: Now, this one is acceptable. Its not very laggy compared to touch events. The only issue is, lets say a player has a weapon and that weapon is going through their opponent, well, the ray WONT be able to calculate through that. Essentially making the hit box not work well in that situation. And could possibly annoy the player.

Hitbox Service(Region 3 hit box): Now, this method is pretty much the ray casting method but WAY better. It doesn’t have much server delay. Another reason why is because it doesn’t have the same issue as ray casting. For example, lets say that a player has a weapon thats going through their opponent. Well, the weapon will STILL attack the opponent. The only issue with this is, some methods may be able to attack through walls. Like the :CreateWithRange Method. I am currently working on a fix for this and should be out soon.

If you have any questions, bugs, or suggestions for the service then feel free to say below!

73 Likes

I just dont know what hitboxes do? Cant default collision of body parts could not be used for hitbox.

3 Likes

You are correct. But these hitboxes are used to do more things. Like weapon hitboxes, npc hitboxes, and anything you want. Having a part welded to the player for a hitbox isn’t that good. Its better to use this instead.

Also hitboxes are used for hit detection for things. Pretty much anything you can imagine, you can do.

3 Likes

Roblox Default .Touched is literally bad (to not say that word), that’s why i never use it and prefer using Modules, i never found a HITBOX Module and just RayCast ones.
Thanks for making this Module, i really needed a module like this. :]

8 Likes

Thank you!! Glad I could help!!

4 Likes

What’s wrong with .Touched? :thinking:

(Except for the fact it’s a bit more exploitable)

1 Like

You should probably explain why .Touched event is bad.

2 Likes

Zones+ was released a ton of time ago too and it’s really great. Can’t find a link to it but if you search for Zones+ you should be able to find it

1 Like

If you connect a touched event to a small object which is fast the hitbox will become innacurate resulting in tunneling (passing thru objects and touched event not firing)

3 Likes

Idk metatables since I’m so trash at them but

module.__index = module
setmetatable({}, module)

What’s this for???

Also, one question, how do I connect it to a part generally?

:CreateWithBox???

2 Likes

You should probably use OverlapParams instead of Region3, as they’re the replacement for Region3 which is deprecated. Unless you are, the source code in the post doesnt look like the full code, but the title says Region3.

It uses overlap params. Not region 3. I just call it that.

1 Like

Both have different uses. Hitbox service can both be used for hitboxes and zones. Zone+’s main use is for zones. Hitbox service in my opinion has more flexibility. Tho I never used zone+ some im not sure.

Can you explain what you mean here?

I meant what hitboxtype should I use to connect to a part.

I’d recommend using :CreateWithPart. Since it connects to the specified part.

Ok but does it create a part or just makes the hitbox?

It makes the hitbox. Just make sure to put the part and it’ll calculate the hitbox automatically where the part is.

1 Like

It’s simple. Its to remove the default setting from the self function. If you try to print self, it’ll say a “function” which is there by default. So thats just used to clear the table so its less messy.

1 Like

Version 1.01, State Updates

Hello! This is the module’s FIRST ever update! This update now allows you to stop hitboxes and allows you to get the state of a hitbox!

How to use:

How to Use

First of all, if you DONT know how to use this module then PLEASE look at the how to set up part of the first post.

The :Stop function allows you to stop a hitbox from going on. This is useful for when you want to stop hitboxes. To use this you must call the :Start function of a hitbox first, then stop it.

local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
local HitBox = HitboxModule:CreateWithRange(script.Parent, script.Parent.Position, 10, OverlapParams.new())
HitBox:Start() -- starts the hitbox
wait(3)
HitBox:Stop() -- stop the hitbox after 3 seconds

Next, the :GetState() function. This function will get weather or not the hitbox has started. True means it has, false means it hasn’t. This is useful for either wanting to see if a hit box is on going. Or preventing errors when stopping a hitbox. Here’s an example of a good time to use the :GetState function. Lets say you have a re-calculating hitbox. But then you stop it. Well, theres a good chance that it may error with the error message of: Cannot get items when hitbox hasn’t started. To start do: hitbox:Start(). This is an issue. In order to fix this we’ll need to use the :GetState Function.
Script:

local RunService = game:GetService("RunService")
RunService.Heartbeat:Connect(function()
	
	local HitboxModule = require(game.ReplicatedStorage.HitboxModuleMain)
	local HitBox = HitboxModule:CreateWithRange(script.Parent, script.Parent.Position, 10, OverlapParams.new())
	HitBox:Start() -- starts the hitbox
	if HitBox:GetState() == true then -- checks state
	local Items = HitBox:GetItems()
	
	wait(1)
		HitBox:Stop() -- stops state
		end
end)