GetPartsInPart() is delayed

I was creating a hitbox system and saw others mentioning GetPartsInPart as the best way to execute hitboxes. The problem I am facing is that the hitbox is delayed if i walk up to a dummy as the hitbox touches them, it does not get damaged. But if i walk away from the dummy, and the hitbox does not look like it is touching them, the dummy gets damaged almost like the hitbox has a delay. I know that I can fix this problem by doing all the hitbox and damage on the local script, but many people say that it is very vulnerable to exploiters.

SERVER SCRIPT:

local REMOTE = game:GetService("ReplicatedStorage"):WaitForChild("EVENT")
local DEBRIS = game:GetService("Debris")
local DB = true

REMOTE.OnServerEvent:Connect(function(PLAYER, ROOTPART, CHARACTER)
	DB = true
	local HITBOX = Instance.new("Part", game.Workspace)
	HITBOX.Anchored = false
	HITBOX.CanCollide = false
	HITBOX.CFrame = ROOTPART.CFrame
	HITBOX.Size = Vector3.new(6,6,6)
	HITBOX.Transparency = 0.5
	HITBOX.Massless = true
	
	local WELD = Instance.new("Weld", ROOTPART)
	WELD.Part0 = ROOTPART
	WELD.Part1 = HITBOX
	
	local PARAMS = OverlapParams.new()
	PARAMS.FilterType = Enum.RaycastFilterType.Exclude
	PARAMS.FilterDescendantsInstances = {ROOTPART, CHARACTER:GetDescendants()}
	
	for i, v in pairs (game.Workspace:GetPartsInPart(HITBOX, PARAMS)) do
		print(v)
		local HUMANOID = v.Parent:FindFirstChild("Humanoid")
		if HUMANOID and DB then
			DB = false
			HUMANOID:TakeDamage(10)
		end
	end
	DEBRIS:AddItem(HITBOX, 0.1)
	
end)

This might be due to the timing of the physics updates. Since GetPartsInPart() checks for collisions based on the current state of the object, there can be a slight delay in detecting parts within the hitbox, especially if the hitbox is moving or if your map is constantly changing.

I’d consider some alternatives, like:

  • Continuous Collision Detection: Use a Touched event on the hitbox part to immediately detect collisions as they happen. This way, you can directly respond to collisions without waiting for the next physics update.
  • Predefined Damage Trigger: Create the hitbox part in advance and use its Touched event to detect when a part enters it. This allows you to respond to collisions in real-time.

Here we’re using the Touched event:

local REMOTE = game:GetService("ReplicatedStorage"):WaitForChild("EVENT")
local DEBRIS = game:GetService("Debris")

REMOTE.OnServerEvent:Connect(function(PLAYER, ROOTPART, CHARACTER)
	local HITBOX = Instance.new("Part")
	HITBOX.Anchored = false
	HITBOX.CanCollide = false
	HITBOX.CFrame = ROOTPART.CFrame
	HITBOX.Size = Vector3.new(6,6,6)
	HITBOX.Transparency = 0.5
	HITBOX.Massless = true
	HITBOX.Parent = game.Workspace

	local WELD = Instance.new("Weld")
	WELD.Part0 = ROOTPART
	WELD.Part1 = HITBOX
	WELD.Parent = ROOTPART

	local function onTouched(hit)
		local HUMANOID = hit.Parent:FindFirstChild("Humanoid")
		if HUMANOID then
			HUMANOID:TakeDamage(10)
			-- Disconnect the touched event to prevent multiple damage instances
			HITBOX.Touched:Connect(nil)
		end
	end

	HITBOX.Touched:Connect(onTouched)

	DEBRIS:AddItem(HITBOX, 0.1)
end)

Its still the same problem i think its because in the server i am a little further behind than where i actually am on screen so the server hitbox is a bit further behind causing the delay, so i dont know if theres a solution without doing it all on the client which i dont want to do

every single good melee system does hit box checks on the client, you just gotta check for things like hitbox size or stuff like that on the server

1 Like

Is your end goal just to do damage when the player touches the NPC?

I just want it to do damage when the hitbox looks like its touching the player so that its a smooth experience, im trying to learn hitbox first because i will add weapons later on

What is firing your remote, and why? This is likely causing your latency.

local PLAYER = game.Players.LocalPlayer
local CHARACTER = PLAYER.Character
repeat wait() until CHARACTER
local ROOTPART = CHARACTER:FindFirstChild("HumanoidRootPart")
local USERINPUT = game:GetService("UserInputService")
local REMOTE = game:GetService("ReplicatedStorage"):WaitForChild("EVENT")

USERINPUT.InputBegan:Connect(function(INPUT, GAMEPROCCESSED)
	if INPUT.KeyCode == Enum.KeyCode.E then
		REMOTE:FireServer(ROOTPART, CHARACTER)
	end
end)
1 Like

Okay, so from my understanding, pressing E will (in the future) run an animation, but in the mean time you want it to check if the arm is touching the NPC ?

As @Miserable_Haven pointed out, you can try doing hit checks on the client and verifying on the server. So to put it all together:

Client-side:

  • Creates and manages the hitbox.
  • Detects collisions locally and sends the collision information to the server using a remote event.

Server-side:

  • Receives the collision information from the client.
  • Creates a temporary hitbox at the reported position for validation.
  • Checks if the reported hit is valid and applies damage if so.

This approach ensures that the game feels responsive by giving immediate feedback on the client while still validating all actions on the server to prevent cheating. It also helps mitigate the effects of network latency.

You’ll need to modify both scripts to meet your needs.

Server Script:

local REMOTE = game:GetService("ReplicatedStorage"):WaitForChild("EVENT")

REMOTE.OnServerEvent:Connect(function(player, hitboxPosition, targetCharacter)
    -- Validate the hit on the server
    local hitbox = Instance.new("Part")
    hitbox.Anchored = true
    hitbox.CanCollide = false
    hitbox.Size = Vector3.new(6,6,6)
    hitbox.Transparency = 1 -- Invisible
    hitbox.Position = hitboxPosition
    hitbox.Parent = game.Workspace

    local humanoid = targetCharacter:FindFirstChild("Humanoid")
    if humanoid and hitbox:IsDescendantOf(game.Workspace) then
        -- Ensure the hitbox overlaps with the target
        local partsInHitbox = game.Workspace:GetPartsInPart(hitbox)
        for _, part in ipairs(partsInHitbox) do
            if part.Parent == targetCharacter then
                humanoid:TakeDamage(10)
                break
            end
        end
    end

    -- Clean up the temporary hitbox part
    hitbox:Destroy()
end)

Client Script:

local REMOTE = game:GetService("ReplicatedStorage"):WaitForChild("EVENT")

local function createHitbox()
    local HITBOX = Instance.new("Part")
    HITBOX.Anchored = false
    HITBOX.CanCollide = false
    HITBOX.Size = Vector3.new(6,6,6)
    HITBOX.Transparency = 0.5
    HITBOX.Massless = true
    HITBOX.Parent = game.Workspace

    return HITBOX
end

local function onHitboxTouched(hitbox, hit)
    local HUMANOID = hit.Parent:FindFirstChild("Humanoid")
    if HUMANOID then
        -- Send hit event to the server
        REMOTE:FireServer(hitbox.Position, HUMANOID.Parent)
    end
end

-- Example: Trigger hitbox creation and detection
local hitbox = createHitbox()
hitbox.Touched:Connect(function(hit) onHitboxTouched(hitbox, hit) end)

-- Assume we have a reference to the player's character
local playerCharacter = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
hitbox.CFrame = playerCharacter.PrimaryPart.CFrame
local weld = Instance.new("Weld")
weld.Part0 = playerCharacter.PrimaryPart
weld.Part1 = hitbox
weld.Parent = playerCharacter.PrimaryPart
1 Like

Thank you, I will just run client side detection and do what @Miserable_Haven has mentioned

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.