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
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
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)
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