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.
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
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.
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
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.
You have to create a Hitbox through a local script, and track who is inside the Hitbox using GetPartBoundsInBox.
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.
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.
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.
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).
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)
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)