Raycast Hitbox 4.01: For all your melee needs!

Is it possible to have it only keep on returning humanoids if it hits them? I have a sword that does a “double slash”(it hits all the body parts) and I don’t know if it will detect it twice.

None of the DetectionModes fit my usage

Use Bypass to make your own hit filtering system, and check to see if the humanoid exists once you hit a part.

hitbox.DetectionMode = RaycastHitbox.DetectionModes.Bypass

hitbox.OnHit:Connect(function(hit)
     local humanoid = hit.Parent:FindFirstChildOfClass("Humanoid")
     
     if humanoid then
          --- Do stuff. The same humanoid will also keep being returned per frame.
     end
end)

Bypass is pretty much the raw hit detection, you can make anything out of it.

Is there some sort of internal api that I can use for filtering? Or should I just recast the hitbox every time its hit.

edit: ill just check for one part

Use tables to keep track of humanoids it hit. For example,

local doubleSlashTargets = {}

hitbox.DetectionMode = RaycastHitbox.DetectionModes.Bypass
hitbox.OnHit:Connect(function(hit)
     local humanoid = hit.Parent:FindFirstChildOfClass("Humanoid")
     
     if humanoid then
          --- Record humanoids hit
          if not doubleSlashTargets[humanoid] then
               doubleSlashTargets[humanoid] = 1 --- Set it to 1 since we just hit them the first time
          else
               doubleSlashTargets[humanoid] += 1 --- Add one to the amount of times we hit them
          end

          --- Ignore additional hits if we reach over 2
          if doubleSlashTargets[humanoid] > 2 then
               return
          end

          humanoid:TakeDamage(100)
     end
end)

I’m not sure how your double slash works but another easy way to make it slash twice is to call :HitStop() once the first slash ends (this resets the targets from the internal filtering), then call HitStart() once the second slash comes out.

In my game, I have a lot of moves that multi-hits, and I use the above strategy of just hitstopping parts that is considered a new slash in the move and works just as well.

Yeah, I thought of this but I thought it would be janky

This might be a problem with my code or with the way I handle my tool animation, but for some reason, the Hitbox points are being offset by quite a bit.

Video of the problem

Here is my code for setting up the hitbox:

function Weapon:SetUpHitbox()
	
	local HitboxParams = RaycastParams.new()
	HitboxParams.FilterDescendantsInstances = {self.Character}
	HitboxParams.FilterType = Enum.RaycastFilterType.Blacklist
	
	local Hitbox = RaycastHitbox.new(self.Tool.Handle)
	Hitbox.RaycastParams = HitboxParams
	Hitbox:SetPoints(self.Tool.Handle, {Vector3.new(0, 0, 1), Vector3.new(0, 0, 2), Vector3.new(0, 0, 3)})
	
	return Hitbox
	
end

Here is my code for the player swinging:

function Weapon:Swing()
	
	if self.SwingDebounce then return end
	self.SwingDebounce = true
	
	if self.LastSwing == 3 then
		self.LastSwing = 1
		self.CurrentSwingAnimation = self.Animations["Swing1"]
	else
		self.LastSwing += 1
		self.CurrentSwingAnimation = self.Animations["Swing"..self.LastSwing]
	end
	
	self.Hitbox:HitStart()
	table.insert(self.PlayingAnimations, self.CurrentSwingAnimation)
	self.CurrentSwingAnimation:Play()
	
	local CurrentAnimationStopped
	CurrentAnimationStopped = self.CurrentSwingAnimation.Stopped:Connect(function()
		
		if not self.IsEquipped then return end
		
		table.remove(self.PlayingAnimations, table.find(self.PlayingAnimations, self.CurrentSwingAnimation))
		self.Hitbox:HitStop()
		self.SwingDebounce = false
		CurrentAnimationStopped:Disconnect()
		
	end)
	
end

I am using this method to animate my tool handle, but it shouldn’t interfere with the hitbox.

Thanks!

Is this server-sided? If it is, check and see if the server sees your character/tool in a different place. Sometimes this can be a problem when you are teleported somewhere or you teleport the tool.

1 Like

My weapon system is in fact server sided. However, the tool is not being teleported, and the weapon creation happens after the player is teleported (a new weapon object is created, and then a cloned tool is parented to the player). Also, I checked to make sure that all the parts of the sword are in the right place, which they are. I did notice the offset stays the same, any suggestions?

Hi, if you don’t mind, would you be able to DM me a barebones repo place containing the weapon and the scripts that you used to parent it to the player? Just to make sure if it’s something I can fix or a user script error that I can help diagnose.

1 Like

Sure, no problem! Thanks for being so supportive and responsive. I really appreciate it!

1 Like

ya be kinda speaking some fax :hot_face:

@TeamSwordphin Hello there! I am using your raycast hitbox for my melee mechanics, but when I slash with the tool it will damage myself and THEN damage someone else. Is there a way to blacklist myself so it won’t detect a local player?

You can use RaycastParams.

hitbox.RaycastParams = RaycastParams.new()
hitbox.RaycastParams.FilterDescendantsInstances = {myCharacter}
hitbox.RaycastParams.FilterType = Enum.RaycastFilterType.Blacklist
1 Like

Solved! Just used CFrame rather than position to teleport the player and it worked like a charm. Not sure why thought :thinking:.

1 Like

I don’t actually use this module, I like it a lot, I find it pretty good, I don’t use it because I don’t work with front-end stuff.

I wonder why you went with still having a “Signal” module anyway? It doesn’t behave like a normal event, it can only have one connection, it doesn’t have any other features like :Wait, they’re more like a callback, so why not just go with a normal callback?

I know you might have you know, keep some things similar to older versions, but I feel like it was kind of a missed opportunity with the release of 4.0, I know that you made that Signal to be as instant as possible, obviously, but in that case you could just make it into a normal callback,
and it would be even faster to call too.

function Hitbox.OnHit(hit)
    print(hit)
end


--// Fire

local _onHit = self.OnHit
if _onHit then
    task.spawn(_onHit, hit) --\\ You can use `task.defer` too, it will run later though of course. Don't know how that affects your use-case.
end

If you were to go with an actual signal instead of just making it into a callback, then I recommend GoodSignal or FastSignal

GoodSignal is interesting for your use-case because it has routine recycling which is really cool for use-cases like yours which might require it to fire super quickly.

How would i convert my v3 to v4?

local plr = script.Parent.Parent.Parent

local char = plr.Character

local idle = char.Humanoid:LoadAnimation(script.Animations.Idle)

local equipped = false

local attacking = false

local RaycastHitbox = require(game.ServerScriptService.RaycastHitboxV2)

local Hitbox = RaycastHitbox:Initialize(script.Parent.Weapon)

durability = 7

local attack1 = char.Humanoid:LoadAnimation(script.Animations.Attack1)

local broken = false

Hitbox.OnHit:Connect(function(hit, humanoid)

if humanoid.Parent ~= char and humanoid.Parent.Handler.Infected.Value == true then

script.Parent.Weapon.Hit:Play()

local damage = math.random(15,35)

local Speed = 25

local Force = 40000

local TotalForce = Force

local KnockBack = Instance.new("BodyVelocity",hit.Parent:FindFirstChild("Torso"))

KnockBack.MaxForce = Vector3.new(TotalForce,TotalForce,TotalForce)

KnockBack.Velocity = plr.Character:FindFirstChild("HumanoidRootPart").CFrame.LookVector * Speed -- based on the direction YOUR character is facing.

game.Debris:AddItem(KnockBack,0.1)

humanoid:TakeDamage(damage)

humanoid.Parent.Actions.Stunned.Value = true

if durability == 0 then

Hitbox:HitStop()

script.Parent.Weapon.Transparency = 1

script.Parent.Weapon.B:Play()

script.Parent.Weapon.ParticleEmitter:Emit(50)

game.ReplicatedStorage.EditGUI:FireClient(plr,"text","Your baseball bat broke.")

broken = true

idle:Stop()

attack1:Stop()

wait(2)

script.Parent:Destroy()

end

durability = durability - 1

end

end)

script.Parent.Equipped:Connect(function()

if not plr.Character.Actions.Stunned.Value == true and not broken then

idle:Play()

equipped = true

else

plr.Character.Humanoid:UnequipTools()

end

end)

script.Parent.Unequipped:Connect(function()

idle:Stop()

equipped = false

end)

script.Parent.Activated:Connect(function()

if not attacking and equipped and not plr.Character.Actions.Stunned.Value == true and durability >= 0 then

attack1:Play()

attacking = true

script.Parent.Weapon.Prepare:Play()

wait(0.16)

Hitbox:HitStart()

script.Parent.Weapon.Swing:Play()

wait(0.4)

Hitbox:HitStop()

wait(2)

attacking = false

wait(0.4)

end

end)

plr.Character.Actions.Stunned.Changed:Connect(function()

plr.Character.Humanoid:UnequipTools()

end)

Good point. I already have a newer version utilizing GoodSignal and task which both supports the single callback and multiple connections (not sure when I’ll update), but thanks for the heads up. I’ve been meaning to get rid of the older signal module for a while now but I decided to wait until tasks were officially released.


@DogGuyTheThird You tried looking at the main post? I put some instructions on how to convert it.

2 Likes

I couldnt find it? can you show it to me?

The bottom of this post contains the new APIs, basically, you just need to switch out the old methods with the new ones. It shouldn’t take too long.

1 Like

so since:

  • Removed RaycastHitbox:Initialize
  • Removed RaycastHitbox:Deinitialize

got removed do I have to:

RaycastHitbox.new
Hitbox:Destroy?