Hey devs,
I made a sword fighting system using hitboxes and raycasts. A huge issue right now is that during combat the detection system barely picks up any hits (even though you can clearly see the player being slashed with the sword). When I hit a dummy it is fine (because it’s immobile), but when you try and hit a moving player, it barely detects.
Please take a look at the code and tell me if there are any improvements I can make.
ServerScript:
local SS = game:GetService("SoundService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local CombatEvent = ReplicatedStorage.Remotes.CombatEvent
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local CombatStatus = Instance.new("StringValue", character)
CombatStatus.Name = "SwordStatus"
CombatStatus.Value = ""
local Hitbox = Instance.new("Part")
Hitbox.Name = "Hitbox"
Hitbox.Anchored = false
Hitbox.Massless = true
Hitbox.CanCollide = false
Hitbox.CanTouch = false
Hitbox.Transparency = 1
Hitbox.Size = Vector3.new(7, 6, 7)
Hitbox.Color = Color3.new(1, 0, 0)
Hitbox.CFrame = character.HumanoidRootPart.CFrame
Hitbox.Parent = character.HumanoidRootPart
local WeldConstraint = Instance.new("WeldConstraint")
WeldConstraint.Part0 = Hitbox
WeldConstraint.Part1 = character.HumanoidRootPart
WeldConstraint.Parent = Hitbox
Hitbox.CFrame = character.HumanoidRootPart.CFrame * CFrame.new(0, 0, 0)
end)
end)
CombatEvent.OnServerEvent:Connect(function(plr, eventType, Arg1)
local Character = plr.Character
local Humanoid = Character:FindFirstChild("Humanoid")
local CombatStatus = Character:FindFirstChild("SwordStatus")
if eventType == "SM1" and CombatStatus.Value == "" then
CombatStatus.Value = "Attacking"
local AT = Humanoid.Animator:LoadAnimation(script[Arg1])
AT:Play()
local Hitbox = Character.HumanoidRootPart:FindFirstChild("Hitbox")
local directions = {
Character.HumanoidRootPart.CFrame.LookVector,
(Character.HumanoidRootPart.CFrame * CFrame.Angles(0, math.rad(10), 0)).LookVector,
(Character.HumanoidRootPart.CFrame * CFrame.Angles(0, math.rad(-10), 0)).LookVector
}
local hitDetected = false
for _, direction in ipairs(directions) do
local ray = workspace:Raycast(Hitbox.Position, direction * 10, RaycastParams.new{
FilterType = Enum.RaycastFilterType.Exclude,
FilterDescendantsInstances = { Character }
})
if ray and ray.Instance and ray.Instance.Parent:FindFirstChild("Humanoid") then
local enemyCharacter = ray.Instance.Parent
if enemyCharacter == Character then
continue
end
hitDetected = true
if enemyCharacter.SwordStatus.Value == "Blocking" then
enemyCharacter.SwordStatus.Value = ""
SS.SwordParry:Play()
AT:Stop()
Character.SwordStatus.Value = "Parried"
task.delay(0.75, function()
Character.SwordStatus.Value = ""
end)
else
local enemyHumanoidRootPart = enemyCharacter:FindFirstChild("HumanoidRootPart")
SS.SwordHit:Play()
if Arg1 == "Stab4" then
enemyCharacter.Humanoid.Health -= 30
else
enemyCharacter.Humanoid.Health -= 10
end
print("dealing damage")
if enemyHumanoidRootPart then
local knockbackForce = Instance.new("BodyVelocity")
knockbackForce.MaxForce = Vector3.new(100000, 0, 100000)
knockbackForce.P = 1000
if Arg1 == "Stab4" then
knockbackForce.Velocity = direction * 50
else
knockbackForce.Velocity = direction * 30
end
knockbackForce.Parent = enemyHumanoidRootPart
game:GetService("Debris"):AddItem(knockbackForce, 0.2)
end
end
break
end
end
if not hitDetected then
SS.SwordSlash:Play()
end
task.delay(0.75, function()
if CombatStatus.Value == "Attacking" then
CombatStatus.Value = ""
print("forced stop")
end
end)
elseif eventType == "Block" and (Character.SwordStatus.Value == "" or Character.SwordStatus.Value == "Blocking") then
if Character.SwordStatus.Value == "" then
Character.SwordStatus.Value = "Blocking"
local BlockAnimation = Humanoid.Animator:LoadAnimation(script.Block)
BlockAnimation:Play()
local UpdateFunction
UpdateFunction = Character.SwordStatus.Changed:Connect(function(newStatus)
if newStatus ~= "Blocking" then
BlockAnimation:Stop()
UpdateFunction:Disconnect()
end
end)
task.delay(1, function()
if Character.SwordStatus.Value == "Blocking" then
Character.SwordStatus.Value = ""
print("Blocking ended automatically")
end
end)
end
elseif Character.SwordStatus.Value == "Blocking" then
Character.SwordStatus.Value = ""
end
end)
ClientScript (Inside every sword):
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local UIS = game:GetService("UserInputService")
local Tool = script.Parent
local CombatEvent = ReplicatedStorage.Remotes.CombatEvent
local Player = Players.LocalPlayer
local AttackNumber = 1
Tool.Activated:Connect(function()
if Player.Character.SwordStatus.Value == "" then
if AttackNumber == 1 then
AttackNumber = 2
CombatEvent:FireServer("SM1", "Stab1")
elseif AttackNumber == 2 then
AttackNumber = 3
CombatEvent:FireServer("SM1", "Stab2")
elseif AttackNumber == 3 then
AttackNumber = 4
CombatEvent:FireServer("SM1", "Stab3")
elseif AttackNumber == 4 then
AttackNumber = 1
CombatEvent:FireServer("SM1", "Stab4")
end
end
end)
UIS.InputBegan:Connect(function(input, processed)
if input.KeyCode == Enum.KeyCode.E and not processed and Player.Character:FindFirstChild(Tool.Name) then
CombatEvent:FireServer("Block")
end
end)
Thank you so much.
-DarkPurpleElixr