Hitbox module having delay updating the players position

Im making a fighting game and I used a hitbox module I created a while ago. When implementing it I noticed that the hitbox was very behind on the players position. Is there any method to fix this delay? Because ive tried many things and it doesnt seem to really change anything.

If you are wondering, I am running at 30-48 ping while in studio. So ping isnt the issue.

Video Proof:
hitbox having delay

Code (ModuleScript):

local hitbox = {}
hitbox.__index = hitbox
local passinfo = {}
local fs = require(game.ReplicatedStorage.Modules.FastSignal)
local Trove = require(game.ReplicatedStorage.Modules.Trove)
function hitbox.MakeHB(cframe,dmg,size,hitboxtime,showhitbox,char)
	
	
	local self = {}
	self.Trove = Trove.new()
	
	self.Hit = self.Trove:Construct(fs.new())
	if showhitbox ==  true then
		hitbox.Transparency = 0.5
	end
	if showhitbox == false then
		hitbox.Transparency = 1
	end
	hitbox.CFrame = cframe
	hitbox.CanCollide = false
	hitbox.Anchored = true
	hitbox.Material = "Neon"
	hitbox.Size = size
	local mainpart = Instance.new("Part",workspace)
	mainp = mainpart
	mainpart.CFrame = hitbox.CFrame
	mainpart.CanCollide = false
	mainpart.Anchored = true
	mainpart.Size = hitbox.Size
	mainpart.Transparency = hitbox.Transparency
	print(tick())
	task.spawn(function()
	self.Trove:AttachToInstance(mainpart)
game.Debris:AddItem(mainpart,hitboxtime)
	
	end)
	
passinfo = self
	return setmetatable(self,hitbox)
	
	
	
end

function hitbox.Scan(char,Position)
	local counterremote = game.ReplicatedStorage.CombatRemotes.CounterRemote
	local params = OverlapParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = {char}
	print(tick())
	local results = game.Workspace:GetPartBoundsInBox(hitbox.CFrame,hitbox.Size,params)
	

	local deb = false
	for _,v in pairs(results) do
			if v.Parent:FindFirstChild("Humanoid") then
			local enemychar = v.Parent
			if v.Parent:GetAttribute("IFrames") == true then return end
			if v.Parent:GetAttribute("Countering") == true then
				print("Countered")
				char:SetAttribute("Countered",true)
				counterremote:FireClient(game.Players:GetPlayerFromCharacter(enemychar),char)
				return 
			end
			--if v:IsDescendantOf(workspace.Attackable) == nil then
			if deb == false then
					passinfo.Hit:Fire(enemychar)
					deb = true
				end
			--	end
		end
	end
end


return hitbox

Thanks in advance!

  1. List item
1 Like

If you want a quick solution, check this module out: HitboxClass | v1.1B | A Powerful OOP-based Hitbox Module

Otherwise, you can implement the same latency compensation they have by adjusting your hitbox’s positioning with something like this:

local DAMPENING = 5

local targetCFrame = NPC_TARGET.CFrame
local adjustedVelocity =  targetCFrame:VectorToObjectSpace(NPC_TARGET.AssemblyLinearVelocity) / DAMPENING

targetCFrame *= adjustedVelocity
2 Likes

Yes, the Player’s position actually updates between 0.05-0.1 seconds later than sending information through remote events. So what I did in my battlegrounds game was adding a remote event that fires from client to server 1/40th of every second (heartbeat rate) indicating the CFrame of the HumanoidRootPart. The server instead of checking the HumanoidRootPart’s CFrame, will instead check for this value sent by the player. And of course, you should add some anticheats on the server so an exploiter can not set off the actual cframe by 5-10+ studs. And for lag issues, this is completely fine, it’s not even 1KB of information sent per second to the server, and the server can handle all these requests.

For content, here is the game I made that is using this kind of system: [🎃PART 2] KJ ARENA - Roblox

2 Likes

This didnt really change anything. Is there anything im doing wrong?
Client

game:GetService("RunService").Heartbeat:Connect(function()
	game.ReplicatedStorage.MainRemotes.UpdatePosition:FireServer()
end)

Server Script

game.ReplicatedStorage.MainRemotes.UpdatePosition.OnServerEvent:Connect(function(player)
	player.Character:SetAttribute("Position",player.Character.HumanoidRootPart.CFrame)
end)
1 Like

bumping this, I still need help

1 Like

I switched over to this module and I still get the same issue

1 Like

Make sure to use :Weld() to weld the Hitbox object to the character’s HumanoidRootPart for the velocity prediction to work.

2 Likes

what @Jexemie meant was he parses the players RootPart’s CFrame as a tuple argument through the RemoteEvent to update the client CFrame on the server faster, not by using the servers interpretation of the client CFrame

Client:

game:GetService("RunService").Heartbeat:Connect(function()
	game.ReplicatedStorage.MainRemotes.UpdatePosition:FireServer(game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame)
end)

Server:

game.ReplicatedStorage.MainRemotes.UpdatePosition.OnServerEvent:Connect(function(player, rootCF)
	player.Character:SetAttribute("Position", rootCF)
end)
2 Likes

The secret to accurate and fast hitboxing lies elsewhere.
For example, now I will tell you a method that is mainly used in Battleground games.

  1. You have to create a Hitbox through a local script, and track who is inside the Hitbox using GetPartBoundsInBox.
  2. You should only handle touches through the local script, and send a signal to the server script to check if the player is stunned and so on.
  3. The method I will write now, in it I add players to a table, then I make a check in the local script if there is a player in the table that has already been touched.
  4. Weld is mandatory, because if you update the Hitbox position via game:GetService(“RunService”), the client will be jerked and the detection will be inaccurate.
  5. You must hit the player not at the moment when the hitbox is removed, but after it is added to the table, otherwise the code will wait until the hitbox is removed and only after it is removed it will execute the hit function (as in my example below).
  6. Also in your example, you are using a module that handles the hitbox. I think it is better to write it not in a module, but in the script in which you create the hitbox. This way the delay will be less and the possibilities will be greater

I also think it is possible to additionally check the distance of the player with the player he is going to hit, using Magnitude

LOCAL SCRIPT ::


local RS = game:GetService("RunService")

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait() or script.Parent

repeat wait(0.1)
until Character:FindFirstChild("HumanoidRootPart") and Character:FindFirstChild("Humanoid")

local overlampParameters = OverlapParams.new()
overlampParameters.FilterType = Enum.RaycastFilterType.Blacklist
overlampParameters.FilterDescendantsInstances = {Character}

local hitboxTransparency = .5 -- hitbox transparency
local x,y,z = 0,  0,  1.5 -- hitbox offset position
local htiboxTime = .16 -- hitbox time

local hitbox = Instance.new("Part")
hitbox.Shape = Enum.PartType.Ball
hitbox.Size = Vector3.new(5,5,5)
hitbox.CanCollide = false
hitbox.Massless = true
hitbox.Transparency = hitboxTransparency
hitbox.Color = Color3.new(1, 0.0973373, 0.181186)
game.Debris:AddItem(hitbox,htiboxTime)

local w = Instance.new("Weld")
w.Part1 = hitbox
w.Part0 = Character.HumanoidRootPart
w.C1 = CFrame.new(x,y,z)

w.Parent = hitbox
hitbox.Parent = workspace

local detecting
local HittedPersones = {}
detecting = RS.Heartbeat:Connect(function(dt)
	if not hitbox.Parent or Character.Humanoid.Health <= 0 then
		if hitbox.Parent then
			hitbox:Destroy()
		end
		detecting:Disconnect()
	else
		local result = workspace:GetPartBoundsInBox(hitbox.CFrame,hitbox.Size,overlampParameters)
		if result then
			for i,v in pairs(result) do
				if v.Parent then
					if v.Parent:FindFirstChild("Humanoid") and v.Parent:FindFirstChild("HumanoidRootPart") and v.Parent ~= Character and not table.find(HittedPersones,v.Parent) then
						table.insert(HittedPersones,v.Parent)
						task.spawn(function()
							-- // Make here signal to remote event to check enemy //
							warn(v.Parent.Name.." Hitted from".." "..Character.Name)
							-- RemoteEvent:FireServer(...)
						end)
					end
				end
			end
		end
	end
end)
2 Likes

What I meant was sending the CFrame of the HRP through the remote event and retrieve it on the server to use it as the CFrame.

I would recommend using a loop or a RunService.RenderStepped function that fires every 1/40th of a second on the client, since connecting the client to the Heartbeat function can cause lag issues.
Client:

-- Client 1:
task.spawn(function()
    while true do
        game.ReplicatedStorage.MainRemotes.UpdatePosition:FireServer(HRP.CFrame)
        task.wait(1/40)
    end
end)
-- Client 2:
local sendpos = 0
RunService.RenderStepped:Connect(function(DeltaTime)
    sendpos += DeltaTime
    if sendpos >= 1/40 then
        sendpos -= 1/40
        game.ReplicatedStorage.MainRemotes.UpdatePosition:FireServer(HRP.CFrame)
    end
end)

Server script:

game.ReplicatedStorage.MainRemotes.UpdatePosition.OnServerEvent:Connect(function(Player, HRPCFrame)
    Player.Character:SetAttribute("Position", HRPCFrame)
end)
1 Like

I feel stupid lol… Sorry for the dumb mistake. This works like a charm though! Thanks a lot!

1 Like