Raycast Hitbox 4.01: For all your melee needs!

New to this, where should I be putting this solution?

Check my github for latest patches. Download version 4.01a

1 Like

Hey I cant find a download for this edit:
nvm found it

Hey I get a bug

19:11:31.733 ReplicatedStorage.Modules.RaycastHitboxV4.Solvers.Bone:39: Expected , got ‘module’ - Studio - Bone:39

with

return solverlocal module = {}

in bone, please help!

can you send me an example place file to further invstigate?

Am I able to use this module on the client for hit-detection?

Yes, thats exactly what this does.

Hit detect on client then fire to server for validation. Thats what Im doing in my current project

Is there a way to only have the debug visualizer visible on the client?

Hi all,

This resource is no longer supported and has been superseded by ShapecastHitbox. While the library is still usable today, it contains some bugs and performance issues that the original team is no longer addressing. You are welcome to fork the project and publish improvements if you wish.

Thank you all for supporting this project for the last 6 years, you all are awesome!

5 Likes

hi there, ive been using this for a while… is there any way to make the hitbox go with the object when you play an animation on the client? so far ive only found out that the hitbox is correct if you play it serversided cuz that prevents hacking the hitboxes if im not wrong…

i would love help because that will def make my experience better

You can play the animation both on client and server.

yes but once i play it on the client the hitbox isnt correct with the tools thats the problem im facing

is there a way to make dismemberment with this?

1 Like

This is a hitbox library, is not related to dismemberment in any way. You can make dismemberment with this module, but it won’t help you do the actual dismemberment itself.

Ie. Detect parts with this library, then make your own interface to decouple the parts from the rig once you do.

1 Like

Is there a way you can detect exactly which attachment hit in the OnHit event?

1 Like

As far as I remember, there isn’t a way. You can go inside the Hitboxcaster and edit it to make it return the attachment on this line:

Change this

ActiveHitboxes[i].OnHit:Fire(part, humanoid, raycastResult, point.Group)

with:

ActiveHitboxes[i].OnHit:Fire(part, humanoid, raycastResult, point.Group, point.Instances[1])

The last parameter will return the attachment.

I know it is no longer being supported but I decided I might as well try my luck, I am making a combat system using this and it works most of the time but sometimes it doesn’t detect.

I have tried a lot of different things to fix it but I am kind of stuck any help would be greatly appreciated. I do the raycast and detection on the client but then I do the damage on the server. It works fine maybe 85% of the time but sometimes it just doesn’t detect the victim

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local LocalPlayer = Players.LocalPlayer
local Tool = script.Parent.Parent
local Mouse = LocalPlayer:GetMouse()

local Character, Humanoid, Animator

local remotesFolder = ReplicatedStorage:WaitForChild("Remotes")
local onHitEvent = remotesFolder:WaitForChild("OnHitEvent")
local RaycastHitbox = require(ReplicatedStorage:WaitForChild("Modules"):WaitForChild("RaycastHitboxV4"))

local Handle = Tool:WaitForChild("Grip")
local Body = Tool:WaitForChild("Grip"):WaitForChild("Cutlass")
local HitboxPart = Tool:WaitForChild("Hitbox")

local VariablesFolder = Tool:WaitForChild("Variables")
local Clicked = VariablesFolder:WaitForChild("Clicked")
local Count = VariablesFolder:WaitForChild("Count")
local Equipped = VariablesFolder:WaitForChild("Equipped")
local Inspect_Ready = VariablesFolder:WaitForChild("Inspect_Ready")

local isSharp = false
local baseDmg = 8
local attackWindows = {}
local HIT_WINDOW = 0.5
local activeHitboxConnection -- Track active hitbox

--// Raycast params
local excludedParts = {workspace:WaitForChild("BulletVisuals")}
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = excludedParts
rayParams.FilterType = Enum.RaycastFilterType.Exclude

local newHitbox = RaycastHitbox.new(HitboxPart)
newHitbox.RaycastParams = rayParams

local Equipped = false

--// Animations + chain timings
local AnimationsFolder = Tool:WaitForChild("Animations")
local animData = {
	{anim = AnimationsFolder:WaitForChild("Slash"), chainTime = 0.7, hitboxDelay = 0.1},
	{anim = AnimationsFolder:WaitForChild("Slash2"), chainTime = 0.6, hitboxDelay = 0.1},
	{anim = AnimationsFolder:WaitForChild("Slash3"), chainTime = 1, hitboxDelay = 0.1}
}
local IdleAnim = AnimationsFolder:WaitForChild("Idle")
local PulloutAnim = AnimationsFolder:WaitForChild("Pullout")

local loadedIdle, loadedPullout
local loadedAttacks = {}

--// Update character refs
local function updateCharacterReferences()
	Character = LocalPlayer.Character
	if Character then
		Humanoid = Character:WaitForChild("Humanoid")
		Animator = Humanoid:WaitForChild("Animator")
		excludedParts = {Character, workspace:WaitForChild("BulletVisuals")}
		rayParams.FilterDescendantsInstances = excludedParts
		newHitbox.RaycastParams = rayParams
	end
end
updateCharacterReferences()
LocalPlayer.CharacterAdded:Connect(updateCharacterReferences)

--// Cleanup old attack windows
local function cleanupWindows()
	local now = tick()
	for i = #attackWindows, 1, -1 do
		if attackWindows[i].finish < now - 1 then
			table.remove(attackWindows, i)
		end
	end
end

--// Improved hitbox management
local function startHitbox(duration)
	-- Stop any existing hitbox first
	pcall(function() newHitbox:HitStop() end)
	if activeHitboxConnection then
		task.cancel(activeHitboxConnection)
		activeHitboxConnection = nil
	end

	-- Start new hitbox
	newHitbox:HitStart()

	-- Use a single consistent timer
	activeHitboxConnection = task.delay(duration, function()
		pcall(function() newHitbox:HitStop() end)
		activeHitboxConnection = nil
	end)
end

--// Equip
local function Tool_Equipped()
	Equipped = true
	updateCharacterReferences()
	if not Animator then return end

	Clicked.Value = false
	loadedIdle = Animator:LoadAnimation(IdleAnim)
	loadedPullout = Animator:LoadAnimation(PulloutAnim)
	loadedAttacks = {}
	for i, data in ipairs(animData) do
		loadedAttacks[i] = Animator:LoadAnimation(data.anim)
	end

	Body.Transparency = 1
	task.wait(0.2)
	Body.Transparency = 0

	--Equipped.Value = true
	loadedPullout:Play()
	task.wait(loadedPullout.Length)
	loadedIdle:Play()
	Clicked.Value = true
	Count.Value = 0
end

--// Unequip
local function Tool_Unequipped()
	Equipped = false
	if loadedIdle then loadedIdle:Stop() end
	if loadedPullout then loadedPullout:Stop() end
	for _, a in ipairs(loadedAttacks) do
		a:Stop()
	end

	-- Clean up hitbox properly
	pcall(function() newHitbox:HitStop() end)
	if activeHitboxConnection then
		task.cancel(activeHitboxConnection)
		activeHitboxConnection = nil
	end

	--Equipped.Value = false
	Count.Value = 0
	Inspect_Ready.Value = true
	task.wait(0.5)
	loadedIdle:Stop()
end

--// Play attack with chain window
local function playAttack(index)
	local data = animData[index]
	local animTrack = loadedAttacks[index]

	-- Stop any other attack animation currently playing
	for _, a in ipairs(loadedAttacks) do
		if a.IsPlaying then
			a:Stop()
		end
	end

	-- Stop any existing hitbox before starting new attack
	pcall(function() newHitbox:HitStop() end)
	if activeHitboxConnection then
		task.cancel(activeHitboxConnection)
		activeHitboxConnection = nil
		newHitbox:HitStop()
	end

	script.Parent.Parent.Swing:Play()
	animTrack:Play()
	

	-- Single timing system for hitbox
	task.delay(data.hitboxDelay, function()
		-- Record attack window
		local startT = tick()
		table.insert(attackWindows, {
			start = startT,
			finish = startT + HIT_WINDOW,
			number = index
		})

		-- Start hitbox with consistent timing
		newHitbox:HitStop()
		startHitbox(HIT_WINDOW)
	end)

	-- Allow chaining early
	task.delay(data.chainTime, function()
		Clicked.Value = true
	end)

	animTrack.Stopped:Connect(function()
		if Count.Value >= #animData then
			Count.Value = 0
		end
	end)
end

--// Main attack handler
local function Tool_Activated()
	updateCharacterReferences()
	if not Character or Character:GetAttribute("Stunned") then return end
	if not (Clicked.Value) then return end

	if Equipped == true then
		
		cleanupWindows()
		Clicked.Value = false
		Count.Value = Count.Value + 1

		if Count.Value > #animData then
			Count.Value = 1
		end

		playAttack(Count.Value)
	end
end

--// Hit detection
newHitbox.OnHit:Connect(function(hitPart, hitHum)
	local now = tick()
	local foundNumber
	for i = #attackWindows, 1, -1 do
		local w = attackWindows[i]
		if now >= w.start and now <= w.finish then
			foundNumber = w.number
			break
		end
	end
	foundNumber = foundNumber or 1
	local finalHit = (foundNumber == #animData)

	-- VFX
	local vfx = game.StarterPlayer.StarterPlayerScripts["Replicator(combat)"].HitVFX.Blood_Attack:Clone()
	vfx.Parent = hitHum.Parent.HumanoidRootPart
	game.Debris:AddItem(vfx, 1)
	for _, v in ipairs(vfx:GetChildren()) do
		if v:IsA("ParticleEmitter") then
			v:Emit(v:GetAttribute("EmitCount"))
		end
	end

	onHitEvent:FireServer(hitHum, isSharp, baseDmg, foundNumber, finalHit)
end)

--// Cleanup loop
task.spawn(function()
	while Tool.Parent do
		task.wait(3)
		cleanupWindows()
	end
end)

--// Connections
Tool.Equipped:Connect(Tool_Equipped)
Tool.Unequipped:Connect(Tool_Unequipped)
Mouse.Button1Down:Connect(Tool_Activated)

I know raycasthitbox does have a sort of inaccuracy issue. Only solution I have for you is to increase the amount of attachments. Also ensure you turn on the debug mode on to see if the rays are actually hitting them.

I know this answer is not what you’re looking for, but ShapecastHitbox also has a raycast option, and requires very minor API changes to migrate to. Accuracy should be improved there.

certainly just detect the body part name and then detect the motor 6d matching it… then you just destroy that motor6d and there you go the body part falls of

This is my problem with the Raycast V4:

  • NPCs that are already exist in the workspace with the script inside it that handles and create the raycasthitbox.new(Tool) things, works normally
  • due to the huge amount of NPC which need to be spawned, I have written an only script for all NPCs also apply the raycasthitbox.new(Tool)
  • I will explain using the picture
  • Every NPCs spawned has this bug
  • without the raycast, spawned NPCs can’t perform more actions
1 Like