Help "smoothing" my combat system scrips

Im working on a combat system and i need the combat to be smooth as posible but it feels pretty janky, and not that fluen
This is my first time designing a melee combat system like this, so i have no idea how to improve on it

The big problems are:
1- The scripts are constantly lagging
2- The cooldown never waits the exact time(if you have 150+ ping then the hitbox and the effects will be delayed)
3- I cant hit mutiple players at the same time
4 - If i work on more than 1 weapon and i add something new i need to add that for every weapon in the game and that will be P a i n
Also im wondering if i should repeat the same script for each weapon or just have one BIG script that controls everything

I tried using module scripts for everything, making the hitbox on the client and replicating the effects on the client too
but none of that helped since the same thing keeps happening and the script is still a big mess of 200+ lines of code

Iā€™m currently using :GetPartsInPart() for the hitbox and i dont plan to change it since the raycast module depends a lot on animation, magnitude is bad bc you can hit people behind you and .touched is trash

local code

------- folders -------
local SoundFolder = game.ReplicatedStorage.Sounds
local AnimationFolder = script:WaitForChild("Anims")
local CombatModule = require(game.ReplicatedStorage.Combat_Handler)

------- objects -------
local player =  game.Players.LocalPlayer
local char = player.Character
if not char or not char.Parent then
	char = player.CharacterAdded:Wait()
end
local hum = char:WaitForChild("Humanoid") 
local equiped = script.Parent.Weapon.Value
local count = 0
local Cooldown = false

------- animations -------
local IdleAnimation = hum:LoadAnimation(AnimationFolder.Idle)
local M1_1 = hum:LoadAnimation(AnimationFolder["1"])
local M1_2 = hum:LoadAnimation(AnimationFolder["2"])
local M1_3 = hum:LoadAnimation(AnimationFolder["3"])
local M1_KICK = hum:LoadAnimation(AnimationFolder["KICK"])

------- equiped events -------
script.Parent.Equipped:Connect(function()
	equiped = true
	IdleAnimation:Play()
end)
script.Parent.Unequipped:Connect(function()
	equiped = false
	IdleAnimation:Stop()
end)

------- events -------
script.Parent.Activated:Connect(function()
	if Cooldown == false and hum:FindFirstChild("Stunned") == nil and hum:FindFirstChild("Blocking") == nil and hum:FindFirstChild("Parrying") == nil and hum:FindFirstChild("Invensible") == nil and hum.Health > 0 then
		Cooldown = true
		if parryingAnimation.IsPlaying or blockingAnimation.IsPlaying then return end
		
		count += 1
		
		script.Parent.Handle.Trail.Enabled = true
		task.delay(0.4, function()
			script.Parent.Handle.Trail.Enabled = false
		end)

		if count == 1 then
			M1_1:Play()
		elseif count == 2 then
			M1_2:Play()
		elseif count == 3 then
			M1_3:Play()
		elseif count == 4 then
			M1_KICK:Play()
		end
		
		task.wait(0.2)
		local hit = CombatModule.Hitbox(char,Vector3.new(8, 4, 5),char.HumanoidRootPart.CFrame + char.HumanoidRootPart.CFrame.LookVector*3,char.HumanoidRootPart,0.15)
		script.Combat:FireServer(count, hit)
		local sound = SoundFolder.SwordSwingSound:Clone()
		sound.Parent = char.HumanoidRootPart
		sound.Pitch = math.random(1,1.2) 
		sound:Play()
		game.Debris:AddItem(sound,0.2)
		
		if count == 4 then 
			count = 0
			task.delay(0.7, function()
				Cooldown = false
			end)
		else 
			task.delay(0.3, function()
				Cooldown = false
			end)
		end
	end
end)

server code

------- folders -------
local ValueFolder = game.ReplicatedStorage.Values
local RemoteFolder = game.ReplicatedStorage.Remotes
local CombatModule = require(game.ReplicatedStorage.Combat_Handler)

------- settings --------
local Damage = 2
local Stun = 0.3
local EStun = 0.2

------- events -------
script.Parent.OnServerEvent:Connect(function(player,count, hit)

	------- objects -------
	local char = player.Character or player.CharacterAdded:Wait()
	local hum =  char:WaitForChild("Humanoid")
	local humrp = char:WaitForChild("HumanoidRootPart")

	CombatModule.vfx(player,player,nil,"DoingMove",0.2)             --Mana Attack vfx
	
	if count == 1 and hum:FindFirstChild("Stunned") == nil and hum:FindFirstChild("Blocking") == nil and hum:FindFirstChild("Parrying") == nil and hum:FindFirstChild("Invensible") == nil then
		CombatModule:add(char,ValueFolder.DoingMove,Stun)

		if hit == nil then return end
			local EHum = hit:FindFirstChild("Humanoid")
			local EHumRp = hit:FindFirstChild("HumanoidRootPart")
			if EHum:FindFirstChild("Parrying") then
				CombatModule:add(char,ValueFolder.Stunned,0.8)
				CombatModule.vfx(player,EHumRp,nil,"Parryed")
			elseif EHum:FindFirstChild("Invensible") then
				CombatModule.vfx(player,EHumRp,nil,"Dodged")
			elseif EHum:FindFirstChild("Blocking") then
				if EHum:FindFirstChild("Blocking").Value == 0 then
					EHum.Blocking:Destroy()
					EHum:TakeDamage(1)
					CombatModule:add(hit,ValueFolder.Stunned,3)
					CombatModule.vfx(player,EHumRp,nil,"Blockbreak")
				else
					EHum.Blocking.Value = EHum.Blocking.Value-1	
					CombatModule.vfx(player,EHumRp,nil,"Blocked")
				end
			elseif EHum:FindFirstChild("DoingMove") then
				CombatModule:add(char,ValueFolder.Stunned,0.8)
				CombatModule.vfx(player,EHumRp,nil,"Parryed")
			else
				--Damage
				EHum:TakeDamage(Damage)

				CombatModule:add(hit,ValueFolder.Stunned,EStun)
				CombatModule.vfx(player,EHumRp,"TestSword","M1")
				RemoteFolder.Camera.SmallBump:FireClient(player)
			end
	elseif count == 4 and hum:FindFirstChild("Stunned") == nil and hum:FindFirstChild("Blocking") == nil and hum:FindFirstChild("Parrying") == nil and hum:FindFirstChild("Invensible") == nil then
		CombatModule:add(char,ValueFolder.DoingMove,Stun)

		if hit == nil then return end
			local EHum = hit:FindFirstChild("Humanoid")
			local EHumRp = hit:FindFirstChild("HumanoidRootPart")
			if EHum:FindFirstChild("Parrying") then
				CombatModule:add(char,ValueFolder.Stunned,0.8)
				CombatModule.vfx(player,EHumRp,nil,"Parryed")
			elseif EHum:FindFirstChild("Invensible") then
				CombatModule.vfx(player,EHumRp,nil,"Dodged")
			elseif EHum:FindFirstChild("Blocking") then
				if EHum:FindFirstChild("Blocking").Value == 0 then
					EHum.Blocking:Destroy()
					EHum:TakeDamage(1)
					CombatModule:add(hit,ValueFolder.Stunned,3)
					CombatModule.vfx(player,EHumRp,nil,"Blockbreak")
				else
					EHum.Blocking.Value = EHum.Blocking.Value-1	
					CombatModule.vfx(player,EHumRp,nil,"Blocked")
				end
			elseif EHum:FindFirstChild("DoingMove") then
				CombatModule:add(char,ValueFolder.Stunned,0.8)
				CombatModule.vfx(player,EHumRp,nil,"Parryed")
			else
				--Damage
				EHum:TakeDamage(Damage)

				local E2 = Instance.new("BodyVelocity", EHumRp)
				E2.maxForce = Vector3.new(25000,25000,25000)
				E2.Velocity = humrp.CFrame.lookVector*50
				game.Debris:AddItem(E2,0.3)
				local E2 = Instance.new("BodyVelocity", humrp)
				E2.maxForce = Vector3.new(25000,25000,25000)
				E2.Velocity = humrp.CFrame.lookVector*10
				game.Debris:AddItem(E2,0.2)

				CombatModule:add(hit,ValueFolder.Stunned,EStun)
				CombatModule.vfx(player,EHumRp,"TestSword","M1")
				RemoteFolder.Camera.SmallBump:FireClient(player)
			end

	else
		script.Parent:FireClient(player)
	end

end)

hitbox module

local Combat_Handler = {}

function Combat_Handler.Hitbox(Character,Size,Position,Weld,Duration)
	local hitpepole = {}
	local hitbox = Instance.new("Part", workspace)
	hitbox.Name = Character.Name.." hitbox"
	hitbox.CanCollide = false
	hitbox.CanQuery = false
	hitbox.Massless = true
	hitbox.BrickColor = BrickColor.new("Really red")
	hitbox.Material = Enum.Material.ForceField
	if script.Visible.Value == true then
		hitbox.Transparency = 0.5
	else
		hitbox.Transparency = 1
	end
	hitbox.Size = Size
	hitbox.CFrame = Position
	
	local weld =  Instance.new("WeldConstraint")
	weld.Part0 = Weld
	weld.Part1 =  hitbox
	weld.Parent =  weld.Part0
	game.Debris:AddItem(hitbox,Duration)
	
	for i=1, 10 do
		for i,v in pairs(workspace:GetPartsInPart(hitbox)) do
			local humanoid = v.Parent:FindFirstChild("Humanoid")
			local enemyHitbox = workspace:FindFirstChild(v.Parent.Name.." hitbox")
			if humanoid and v.Name == "Hitbox" and v.Parent ~= Character then
				if not table.find(hitpepole, v.Parent) then
					table.insert(hitpepole, v.Parent)
					game.Debris:AddItem(enemyHitbox,0)
					return v.Parent
				end
			end
		end
		task.wait(Duration/10)
	end
end

function Combat_Handler.add(Player, Character, action, duration)
	local Value = action:Clone()
	Value.Parent = Character.Humanoid
	game.Debris:AddItem(Value,duration)
end

function Combat_Handler.remove(Player, Character, action)
	if Character.Humanoid:FindFirstChild(action) then
		Character.Humanoid:FindFirstChild(action):Destroy()
	end
end

function Combat_Handler.vfx(player,target,class,action,extra)
	for i,v in pairs(game.Players:GetChildren()) do
		game.ReplicatedStorage.Remotes.VFX:FireClient(v,target,class,action,extra)
	end
end

game:GetService("RunService").Heartbeat:Connect(function()
	for i,v in pairs(workspace.Entities:GetChildren()) do
		if v.Humanoid:FindFirstChild("Stunned") then
			v.Humanoid.WalkSpeed = 0
			v.Humanoid.JumpPower = 0
		elseif v.Humanoid:FindFirstChild("Blocking") then
			v.Humanoid.WalkSpeed = 1
			v.Humanoid.JumpPower = 0
		elseif v.Humanoid:FindFirstChild("Parrying") then
			v.Humanoid.WalkSpeed = 1
			v.Humanoid.JumpPower = 0
		elseif v.Humanoid:FindFirstChild("IsRunning") then
			v.Humanoid.WalkSpeed = 20
			v.Humanoid.JumpPower = 50
		else
			v.Humanoid.WalkSpeed = 10
			v.Humanoid.JumpPower = 50
		end
	end
end)

return Combat_Handler

If you found any other error or bug in the scripts just tell me

here is a place to test the combat:
https://www.roblox.com/games/9205710583/Public-Combat-TestV1

3 Likes