[Code review request] Need feedback for my combat system code
Hi everyone,
I’m new to game development and working on the Combat System. I would greatly appreciate it if experienced developers could review my code and give feedback. Your insights will help me improve and learn best practices.
Best regards,
thanhgamer091206
Ragdoll module:
Game Link:
Local script:
-- [[ services ]] --
local players = game:GetService('Players')
local userinput_service = game:GetService('UserInputService')
local replicated_storage = game:GetService('ReplicatedStorage')
local runservice = game:GetService('RunService')
-- [[ varibles ]] --
local tool = script.Parent
local remote_event = script.Parent:WaitForChild('RemoteEvent')
local local_player = players.LocalPlayer
local character = local_player.Character or local_player.CharacterAdded:Wait()
local animations = replicated_storage:WaitForChild('animations')
local boolean = false
local attacking = false
local action = ''
local combo = 0
local combo_timer = tick()
-- [[ functions ]] --
local function check(character, propertise)
for _, v in pairs(propertise) do
if character:FindFirstChild(v) then
return true
end
end
return false
end
-- [[ main ]] --
tool.Equipped:Connect(function()
boolean = true
remote_event:FireServer('equip', true)
end)
tool.Unequipped:Connect(function()
boolean = false
remote_event:FireServer('equip', false)
end)
local delay_test = tick()
userinput_service.InputBegan:Connect(function(input, is_typing)
if is_typing or boolean == false or attacking == true or check(character, {'action', 'stun', 'block'}) then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
print(tick() - delay_test)
if tick() - combo_timer >= 2 then
combo = 0
end
if combo >= 5 then
combo = 0
end
action = 'm1'
combo += 1
combo_timer = tick()
remote_event:FireServer('m1', combo)
end
if input.KeyCode == Enum.KeyCode.F then
remote_event:FireServer('block', true)
end
end)
userinput_service.InputEnded:Connect(function(input, is_typing)
if is_typing or boolean == false or attacking == true then return end
if input.KeyCode == Enum.KeyCode.F then
remote_event:FireServer('block', false)
end
end)
remote_event.OnClientEvent:Connect(function(command, ...)
if command == 'attack' then
if attacking == true then return end
action = 'm1'
attacking = true
local animation_name = select(1, ...)
local track = character.Humanoid:LoadAnimation(animations:FindFirstChild(animation_name))
track:Play()
track:AdjustSpeed(1.25)
track.Stopped:Once(function()
track:Destroy()
end)
wait(.5)
attacking = false
action = ''
end
if command == 'block' then
action = 'block'
local track = character.Humanoid:LoadAnimation(animations:FindFirstChild('block'))
track:Play()
while character:FindFirstChild('block') do
wait()
end
track:Stop()
track:Destroy()
action = ''
end
end)
runservice.RenderStepped:Connect(function()
local speedrun = 18
local jump = 50
if action == 'm1' then
speedrun = 8
jump = 0
end
if action == 'block' then
speedrun = 8
end
character.Humanoid.WalkSpeed = math.max(0, speedrun)
character.Humanoid.JumpHeight = math.max(0, jump)
end)
Script in tool:
-- [[ services ]] --
local server_storage = game:GetService('ServerStorage')
local replicated_storage = game:GetService('ReplicatedStorage')
-- [[ varibles ]] --
local remote_event = script.Parent:WaitForChild('RemoteEvent')
local hitbox_module = require(server_storage:WaitForChild('hitbox_module'))
local bindable_event = replicated_storage:WaitForChild('Damage')
local effect_event = replicated_storage:WaitForChild('effect')
local boolean = false
local cache = {}
-- [[ functions ]] --
local function check(character, propertise)
for _, v in pairs(propertise) do
if character:FindFirstChild(v) then
return true
end
end
return false
end
-- [[ main ]] --
remote_event.OnServerEvent:Connect(function(player, command, ...)
local character = player.Character
if command == 'equip' then
local is_equip = select(1, ...)
if type(is_equip) ~= 'boolean' then player:Kick('WTF ??') end
boolean = is_equip
else
if boolean == false then player:Kick('SPOOF ?') end
if boolean == true and not character:FindFirstChildWhichIsA('Tool') then player:Kick('SPOOF ?') end
end
if command == 'm1' then
if check(character, {'action', 'stun', 'block'}) then return end
local combo = select(1, ...)
remote_event:FireClient(player, 'attack', 'hit'..combo)
wait(0.25)
hitbox_module.validate_hit(character, Vector3.new(5, 5, 3), CFrame.new(0, 0, -4), {
damage = 1.25,
type = 'classic',
combo = combo
})
if combo == 5 then
local flag = Instance.new('BoolValue')
flag.Parent = character
flag.Name = 'action'
game.Debris:AddItem(flag, .75)
end
end
if command == 'block' then
if check(character, {'action', 'stun'}) then return end
local is_blocking = select(1, ...)
if type(is_blocking) ~= 'boolean' then player:Kick('WTF ??') end
if is_blocking == true then
local flag = Instance.new('IntValue')
flag.Parent = player.Character
flag.Name = 'block'
flag.Value = 5
remote_event:FireClient(player, 'block', is_blocking)
else
if character:FindFirstChild('block') then
character:FindFirstChild('block'):Destroy()
end
end
end
end)
Server script:
-- [[ services ]] --
local replicated_storage = game:GetService('ReplicatedStorage')
local server_storage = game:GetService('ServerStorage')
local player_service = game:GetService('Players')
-- [[ varibles ]] --
local bindable_event = replicated_storage:WaitForChild('Damage')
local effect_event = replicated_storage:WaitForChild('effect')
local ragdoll_module = require(script.Parent.R6Ragdoll.ModuleScript)
-- [[ main ]] --
player_service.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
repeat
character.Parent = workspace.characters
wait()
until character.Parent == workspace.characters
end)
player.CharacterRemoving:Connect(function(character)
character:Destroy()
end)
end)
player_service.PlayerRemoving:Connect(function(player)
player:Destroy()
end)
workspace.characters.ChildAdded:Connect(function(obj)
ragdoll_module:Setup(obj)
end)
bindable_event.Event:Connect(function(player_character, target_character, humanoid, propertise)
local player = player_service:GetPlayerFromCharacter(target_character)
if humanoid ~= target_character.Humanoid then
player:Kick('SPOOF ???')
end
if target_character:FindFirstChild('ragdoll') then
return
end
if propertise.block and propertise.block.Value > 0 then
effect_event:FireAllClients('m1', 'block', target_character, propertise)
propertise.block.Value -= 1
if propertise.block.Value == 0 then
propertise.block:Destroy()
else
return
end
end
local stun_flag = Instance.new('BodyGyro')
stun_flag.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
stun_flag.CFrame = target_character.HumanoidRootPart.CFrame
stun_flag.Name = 'stun'
stun_flag.Parent = target_character.HumanoidRootPart
game.Debris:AddItem(stun_flag, 0.25)
if propertise.combo >= 5 then
stun_flag:Destroy()
local ragdoll_flag = Instance.new('BoolValue')
ragdoll_flag.Name = 'ragdoll'
ragdoll_flag.Parent = target_character
game.Debris:AddItem(ragdoll_flag, 2)
local body_vec = Instance.new('BodyVelocity')
body_vec.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
body_vec.Velocity = player_character.HumanoidRootPart.CFrame.LookVector * 40
body_vec.Parent = target_character.HumanoidRootPart
game.Debris:AddItem(body_vec, 0.1)
target_character.RagdollTrigger.Value = true
delay(2, function()
target_character.RagdollTrigger.Value = false
end)
end
effect_event:FireAllClients('m1', 'hit', target_character, propertise)
humanoid:TakeDamage(propertise.damage)
end)
for _, v in pairs(workspace.characters:GetChildren()) do
ragdoll_module:Setup(v)
end