Raycast Hitbox 4.01: For all your melee needs!

I’m fairly sure this is simply a replication bug on roblox end but if the stand is controlled by a player this can be easily fixed by moving the hitboxing to the clientside and utilizing proper server sanity checks. This would make your stand gameplay much more responsive in turn for a little bit more work serversided. Refer to a the knife posts examples above if you need some examples of sanity checking.

1 Like

Okay, I can try making combat client-sided. Any idea how to replicate this to other players? I’m a little new to client-sided and server-sided stuff…

Well, you can possibly keep the stand as it is on the server side, but keep the hit detection logic on the client side. Whenever you (the player) commands the stand to attack, the client will also take care of the hit detection (so this means using raycasthitbox on a client’s localscript). Once the stand gets a hit in the localscript, you can use a RemoteEvent to tell the server to damage the target that the stand hit.

Then, refer to this example post below on how the server can interpret the target. You don’t want to damage the target immediately without sanity checks. This ensures you have proper replication to all players while having adequate hitboxes.

Thank you so much, @TeamSwordphin ! You’re very generous and helpful! Here’s the final product, thanks to you:

https://gyazo.com/9416feadb6bc3f271580b132ba5e9291

dont mind that last buggy part lol…

1 Like

Looking good! Happy to help and good luck on your project :smiley:

2 Likes

Hey! I have a question about this module:
I have this sword with a few DmgPoints in it.
When I put it in StarterPack and swing it, the hitboxes work fine.
However, when I put it in ServerStorage and give it to the player via a script the tool works, but the hitboxes don’t (I turned on debug mode, lines weren’t showing up)

Any idea why this is happening?

Strange. Can i see the tool script where you initialized the Hitbox? Maybe i can catch something that you haven’t.

Hello, I upgraded the version of this module from 2.3 to 3.2 and now I am getting this error:

screenshot of code:

screenshot of error:
image

It seems the HitStart and HitStop methods don’t exist when I create a new hitbox. In the documentation the examples are still using the HitStart and HitStop methods so I’m guessing you didn’t remove them. Is there something obvious that I’m doing incorrectly?

Does any print messages come up in the output from RaycastHitbox? (Assuming warning messages are turned on). Are you deinitializing or destroying the hitbox anywhere?

Right when you responded I found the issue. The issue was that the CollectionService tag you have added to the object passed into the Initialize method got removed whenever I equipped it (I passed a tool into the object parameter) which caused the hitbox to deinitialize.

I don’t know why the tag got removed every time I equipped the tool but I managed to fix it by just passing in a different object that contained the DmgPoints.

Hmm that’s strange. Never had that problem when I was working with tools. As far as I know the tag is only removed when the instance you passed it in is destroyed.

Yeah, here you go:

local Players = game:GetService("Players")
local player 
repeat wait(); Players:FindFirstChild(script.Parent.Parent.Name) until script.Parent.Parent:IsA("Model")

local player = Players:FindFirstChild(script.Parent.Parent.Name)
local character = player.Character or player.CharacterAdded:Wait()
while character.Parent ~= workspace do
	if character.Parent ~= workspace then
		character = player.Character or player.CharacterAdded:Wait()
	end
	game:GetService("RunService").RenderStepped:Wait()
end
local humanoid = character:WaitForChild("Humanoid")

local trail = script.Parent.Blade.Trail

local currentlyAttacking = false
local canAttack = script.Parent.canAttack

--Hitboxes--
local RS = game:GetService("ReplicatedStorage")
local RAYCAST_HITBOX = require(RS.RaycastHitboxV3)

local ignoreList = {character}
local newHitbox = RAYCAST_HITBOX:Initialize(script.Parent.Blade, ignoreList)

newHitbox.OnHit:Connect(function(hit, humanoid)
	if character.RageActive.Value == true then
		humanoid:TakeDamage(10 * 1.5)
	else 
		humanoid:TakeDamage(10)
	end
	
	if hit.Name == "HeadHitbox" then
		if humanoid.Health <= humanoid.MaxHealth * 1/10 then
			for _, v in pairs(hit:GetChildren()) do
				v:Destroy()
			end

			humanoid.Head:Destroy()

			local blood = game.ReplicatedStorage.Blood:Clone()
			blood.Parent = humanoid.Parent.Torso
		end	
	end
end)

--Attack Functions--

function Slash()
	newHitbox:HitStart()
	canAttack.Value = false
	currentlyAttacking = true
	trail.Enabled = true
	wait(0.35)
	newHitbox:HitStop()
	trail.Enabled = false
	currentlyAttacking = false
end

function Attack()
	if canAttack.Value and not currentlyAttacking then
		Slash()
	end
end

script.Parent.cooldownFalse.OnServerEvent:Connect(function()
	canAttack.Value = true
end)

script.Parent.Activated:Connect(Attack)

The thing is that I have another tool which essentially has the same code in ServerStorage, and its given the exact same way; and only that one works.

Hmm how are you giving the tool to the player? I could not replicate the problem with the code in your post.


My tests has this one script in ServerScriptService:

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		wait(1)
		game.ServerStorage.Tool:Clone().Parent = player.Backpack
	end)
end)

And here’s a slightly modified version of your script for my testing (I doubt I fixed the main problem though for any edits I did)

local Players = game:GetService("Players")
local player 
repeat wait(); Players:FindFirstChild(script.Parent.Parent.Name) until script.Parent.Parent:IsA("Model")

local player = Players:FindFirstChild(script.Parent.Parent.Name)
local character = player.Character or player.CharacterAdded:Wait()
while character.Parent ~= workspace do
	if character.Parent ~= workspace then
		character = player.Character or player.CharacterAdded:Wait()
	end
	game:GetService("RunService").RenderStepped:Wait()
end
local humanoid = character:WaitForChild("Humanoid")

local currentlyAttacking = false
local canAttack = script.Parent.canAttack

--Hitboxes--
local RS = game:GetService("ReplicatedStorage")
local RAYCAST_HITBOX = require(RS.RaycastHitboxV3)

local ignoreList = {character}
local newHitbox = RAYCAST_HITBOX:Initialize(script.Parent.Handle, ignoreList)
newHitbox:DebugMode(true)

newHitbox.OnHit:Connect(function(hit, humanoid)
	print(hit)
end)

--Attack Functions--

function Slash()
	newHitbox:HitStart()
	canAttack.Value = false
	currentlyAttacking = true
	wait(0.35)
	newHitbox:HitStop()
	currentlyAttacking = false
	
	canAttack.Value = true
end

function Attack()
	if canAttack.Value and not currentlyAttacking then
		Slash()
	end
end

--- I moved canAttack.Value = true into the Slash() function
--script.Parent.cooldownFalse.OnServerEvent:Connect(function()
--	canAttack.Value = true
--end)

script.Parent.Activated:Connect(Attack)

Upon cloning and parenting the tool to the player’s backpack, the hitbox and tool work as expected. Is the RaycastModule printing anything in the output? Does it see any of the attachments in the sword?

1 Like

It does indeed see the attachments, but it doesn’t create the hitbox.
Here is the giver script:

local click = script.Parent.ClickDetector
local weapon = game.ServerStorage.Longsword

click.MouseClick:Connect(function(player)
	local clone = weapon:Clone()
	clone.Parent = player.Backpack
	
	local spawns = workspace.Spawns
	local random = math.random(1, 8)

	player.Character.HumanoidRootPart.Position = spawns["Spawn" .. random].Position
end)

I was wondering if I should use MoveTo instead of .Position because of a side issue, where the player would be outside of the arena walls on other players’ screens ignore this i just replaced it with moveto

Huh. Replacing it seems to have fixed it… for some reason.

1 Like

There should be methods to change/remove the object that is being used to find the DmgPoints that is passed into the Initialize method but still keep the original object as an identifier to the hitbox. (sorry if this sounds confusing)

Could be useful if you want to make alternating hitboxes (if you have 2 parts containing DmgPoints and you want to alternate between them each attack; useful if you want to add fists into your game).
Could also be useful if you want to remove the object entirely and only use points set with SetPoints for a certain attack or something.

1 Like

Sounds cool, though I feel doing something like this is more adequate than shoving more convoluted features on hitboxes (and you can further simplify this with a hitbox wrapper which doesn’t take too long either):

local fist_hitboxes = {leftArm:Initialize(leftArm, {char}), rightArm:Initialize(rightArm, {char})}
local currentHitbox = fist_hitboxes[1]

currentHitbox:HitStart()
wait(1)
currentHitbox:HitStop()

currentHitbox = fist_hitboxes[2]
currentHitbox:HitStart()
wait(1)
currentHitbox:HitStop()

And I do like the SetPoints idea where it doesn’t need an object, perhaps using a vector point in space instead.

1 Like

Would i be able to use humanoid and part detection at once? I want my sword to detect another sword’s blade, Or detect a part so it stops the swing like in mordhau.

(For what i’m making, I want a bottle that you can hit people with, But if you hit a part it breaks and deals more damage.)

Using part detection will no longer check for humanoids automatically. Doesn’t mean it no longer works, it just means you will have to check it yourself.

local hitbox = raycastHitbox:Initialize (object, ignoreList)

hitbox:PartMode(true)

hitbox.OnHit:Connect(function (hit)
     if hit.Parent:FindFirstChildOfClass("Humanoid") then

     end

     if hit.Name == "Blade" then

     end
end)

Oh, I see, Thank you very much!

1 Like

Hey I was wondering how would this be used for Melee combat uses? (fist), I just cannot seem to understand it.
Sorry if you’ve already answered this question, I didn’t see!