Don't Know How to Make Hitbox System Account for Player Velocity

For my asymmetrical game (how original I know) I want to have hitboxes similar to that of Forsaken’s or like Pwned By 14:00, with how multiple hitboxes are spawned with one swing, and the code that I have so gracefully borrowed from DoomHammerYT does this correctly. However the system doesn’t account for velocity, which is the main issue, as the hitboxes lags behind the player while moving and the hitboxes get thrown if the player turns too fast.

The 3 lines of code above from Adi_DK is a solution that works for forsaken, but attempting to insert the code into the hitbox script doesn’t work, as I believe that the way the createHitbox function actually creates the hitboxes, attempting to combine the lines on top, is more difficult than I thought it would be.

Is there a simpler way to either make the hitboxes’s offset value adapt to velocity, or a way to combine the code?

The solution that I currently have is just an extremely simple and quite terrible, increasing the offset when a certain speed is reached, which still produces the issue of the hitboxes getting thrown when turning, and the hitboxes generally being disjointed


local pingOffset = 6.5 - 10 * math.clamp(player:GetNetworkPing(), 0, 0.3)

local velocityOffset = hitboxPart.CFrame:VectorToObjectSpace(primaryPart.AssemblyLinearVelocity)

hitboxPart.CFrame *= CFrame.new(velocityOffset / pingOffset)

-- the code i have no idea how to implement above 

-- above code by Adi_DK

-- beneath code by DoomHammerYT

local function createHitbox(damage, size, offset, hrp, hitboxes, touchedTable)
	local hitbox = Instance.new("Part")
	hitbox.CanCollide = false
	hitbox.Transparency = 0.75
	hitbox.Size = size
	hitbox.Parent = workspace
	hitbox.CFrame = hrp.CFrame * CFrame.new(offset)
	hitbox.Anchored = true
	
	table.insert(hitboxes, hitbox)
	
	local touchedParts = workspace:GetPartBoundsInBox(hitbox.CFrame, hitbox.Size)
	for i, part in touchedParts do
		table.insert(touchedTable, part)
	end
end

m1Event.OnServerEvent:Connect(function(player, damage, size, offset, startup, Time, increment)
	task.wait(startup) -- startup time
	
	local hitboxes = {}
	local touchedParts = {}
	local damagedPlayers = {}
	
	local character = player.Character or player.CharacterAdded:Wait()
	local hrp = character:WaitForChild("HumanoidRootPart")
	local humanoid = character:WaitForChild("Humanoid")
	
	local breakLoop = false
	
	for i = 1, math.floor(Time / increment), 1 do
		createHitbox(damage, size, offset, hrp, hitboxes, touchedParts)
		
		for i, part in touchedParts do
			if table.find(hitboxes, hitboxes[part]) or table.find(damagedPlayers, damagedPlayers[part.Parent.Name]) or not part.Parent:FindFirstChild("Humanoid") then 
				table.remove(touchedParts, touchedParts[part]) -- removes hitboxes, non-charcater objects, and anything already damaged
			else
				if part.Name == "playerHitbox" and part.Parent.Name ~= character.Name then
					table.insert(damagedPlayers, part.Parent.Name)
					part.Parent:FindFirstChild("Humanoid"):TakeDamage(damage)
					breakLoop = true -- once hit it will stop casting the hitboxes
				end
			end
		end
		
		table.clear(touchedParts)
		
		task.wait(increment)
		
		if breakLoop then break end
	end
	
	for i, hitbox in hitboxes do
		hitbox:Destroy()
	end
end)
1 Like

The problem isn’t velocity, it’s that your hitboxes are static.

In createHitbox you anchor the part and only set its CFrame once:

hitbox.CFrame = hrp.CFrame * CFrame.new(offset)
hitbox.Anchored = true

After that, the hitbox never updates, so when the player moves or turns quickly it lags behind or gets “thrown”. That’s why adapting the offset using velocity doesn’t really fix it.

Forsaken-style systems don’t offset hitboxes using velocity — they continuously update the hitbox CFrame every frame (Heartbeat/Stepped) relative to the HumanoidRootPart. This automatically accounts for both movement and rotation without any velocity math.

So instead of modifying the offset, keep the hitbox following hrp.CFrame while it exists.

1 Like

I am a tiny bit confused on how to do this, I am not sure how to go about making the hitbox itself follow the player.

I only really know a bit of basic knowledge of scripting, and the attempts i’ve done implement this are amateur at best, and still just putting a RS.heartbeat on the problem and still suffering the same issue of the Cframe not updating, except with the hitbox just not disappearing.

1 Like

Could you please provide a video of what’s going wrong? The code itself from my quick look seems fine.

Initial guesses to the problem would be the increment parameter - are you sure its being passed through correctly?

2 Likes

With my game, the hitbox is trailing behind the player, as opposed to how pwned’s hitboxes spawn, which is directly in the middle of the player.

The solution that I tried was simply just spawning the hitbox every frame, which doesn’t solve the problem of the hitbox trailing behind.

The way the el_tacosg is recommending is to keep updating the hitboxes location relative to the hrp.CFrame which I don’t really know how to do.

Add some range to your hitboxes.

Luckily we can implement this relatively easily because of the offset parameter given here. We just need to find a suitable argument to ensure the hitbox is offsetted forward, to account for the ‘lag.’

createHitbox(damage, size, offset, hrp, hitboxes, touchedParts)

What I would personally do is change this offset parameter to instead look for a number value instead of a CFrame called range. If we do this we can easily move the hitbox forward by multiplying the hrp’s current CFrame range studs forward, as seen here:

hitbox.CFrame =  CFrame.new(hrp.Position + hrp.CFrame.LookVector * range, hrp.Position + hrp.CFrame.LookVector * 20)

This new line of code instead positions the hitbox directly onto the character, facing forwards, while also offsetting the hitbox forward to ensure it remains in front of the player.

Hope this helps!

1 Like