Having Trouble with my Combat System (R6)

Hello developers and scripters!

Problem: Both attacks are linked to the same attacking body part

I am trying to make a barrage attack for my little fun creation. The problem is that, for my attacks, punch and barrage, I can only set the attack to one body part (unless you can fix that). As in, the punch is set to the Right Arm and the barrage is, too.

I was thinking on adding two invisible parts on the hands of the player, but I don’t know how to do that (welding a part to the arm).

Since I am not stuck to only 2 hours of creating this combat system, like I did here: First Combat System in Two Hours! (I gave the game file here)

I can spend as much time as I want because it’s not a 2 hour challenge. So I added effects (also the first time)

The updated script (see the link and download the game file to see the original):

local char = script.Parent
local animIsPlaying = false
local combatParts = {
	Punch = char['Right Arm'],
	Uppercut = char['Left Arm'],
	Kick = char['Right Leg'],
	Barrage = char['Right Arm']
}
local damage = {
	Punch = 10,
	Uppercut = 15,
	Kick = 22,
	Barrage = 3 -- Per hit
}
local cooldown = {
	Punch = 0.5,
	Uppercut = 3,
	Kick = 5,
	Barrage = 10
}
local cooldownActive = {
	Punch = false,
	Uppercut = false,
	Kick = false,
	Barrage = false
}

local hum = char:WaitForChild('Humanoid')
local ev = char.Attack
local ev2 = char.OnCooldown

ev.OnServerEvent:Connect(function(plr, attack)
	if not animIsPlaying then
		local anim = hum.Animator:LoadAnimation(script[attack])
		local attacks = 0
		local barrageEffects = {
			Blows = nil,
			Light = nil
		}
		
		if not cooldownActive[attack] then
			anim.Priority = Enum.AnimationPriority.Action
			anim:Play()
			
			print('Attack: '.. tostring(attack))
			
			cooldownActive[attack] = true
			ev2:FireClient(plr, attack, cooldownActive[attack])
			
			-- Below is just speeds for specific attacks
			
			if attack == 'Kick' then
				hum.WalkSpeed = 0
			elseif attack == 'Barrage' then
				hum.WalkSpeed = 3
			end
			
			animIsPlaying = true
			
			-- Below, hum2 is the target
			
			if attack == 'Barrage' then
				combatParts[attack].Touched:Connect(function(hit)
					local hum2 = hit.Parent:FindFirstChild('Humanoid')
					
					if hum2 then
						if animIsPlaying and not (hit.Parent:FindFirstChild('Torso'):FindFirstChild('Blows') or hit.Parent:FindFirstChild('Torso'):FindFirstChild('Light')) then
							for i, v in pairs(workspace.Target:GetChildren()) do
								local newV = v:Clone()
								
								newV.Parent = hit.Parent.Torso
								newV.Enabled = true
								
								barrageEffects[v.Name] = newV
								
								print('Added effects to target')
							end
						elseif animIsPlaying then
							barrageEffects.Blows = hit.Parent.Torso.Blows
							barrageEffects.Light = hit.Parent.Torso.Light
						end
						
						
						if attacks < 20 and animIsPlaying then
							attacks += 1
							
							hum2:TakeDamage(damage[attack])
						end
					end
				end)
			else
				wait(anim.Length / 2) -- Wait until the attacking body part is actually in motion
				
				combatParts[attack].Touched:Connect(function(hit)
					local hum2 = hit.Parent:FindFirstChild('Humanoid')
					
					if hum2 then
						if attacks < 1 and animIsPlaying then
							attacks += 1
							
							hum2:TakeDamage(damage[attack])
						end
					end
				end)
			end
			
			anim.Stopped:Wait()
			
			if barrageEffects.Blows then -- No need of adding "~= nil" after
				print('Destroyed barrage effects')
				
				barrageEffects.Blows:Destroy()
				barrageEffects.Light:Destroy()
			end
			
			hum.WalkSpeed = 20
			animIsPlaying = false
			
			wait(cooldown[attack])
			
			cooldownActive[attack] = false
			ev2:FireClient(plr, attack, cooldownActive[attack])
		end
	end
end)

Thank you in advance! All help appreciated! :slight_smile:

1 Like

Two posts I’ve created and got barely any responses. Please help!

Change your script to this:

--//Variables
local char = script.Parent
local hum = char:WaitForChild('Humanoid')
local ev = char.Attack
local ev2 = char.OnCooldown

--//Controls
local animIsPlaying = false

--//Tables
local combatParts = {
	Punch = {char:WaitForChild("Right Arm")},
	Uppercut = {char:WaitForChild("Left Arm")},
	Kick = {char:WaitForChild("Right Leg")},
	Barrage = {char:WaitForChild("Right Arm"), char:WaitForChild("Left Arm")}
}

local damage = {
	Punch = 10,
	Uppercut = 15,
	Kick = 22,
	Barrage = 3 -- Per hit
}

local cooldown = {
	Punch = 0.5,
	Uppercut = 3,
	Kick = 5,
	Barrage = 10
}

local cooldownActive = {
	Punch = false,
	Uppercut = false,
	Kick = false,
	Barrage = false
}

--//Functions
ev.OnServerEvent:Connect(function(plr, attack)
	if not animIsPlaying then
		local anim = hum.Animator:LoadAnimation(script[attack])
		local attacks = 0
		local barrageEffects = {
			Blows = nil,
			Light = nil
		}

		if not cooldownActive[attack] then
			anim.Priority = Enum.AnimationPriority.Action
			anim:Play()

			print('Attack: '.. tostring(attack))

			cooldownActive[attack] = true
			ev2:FireClient(plr, attack, cooldownActive[attack])

			-- Below is just speeds for specific attacks

			if attack == 'Kick' then
				hum.WalkSpeed = 0
			elseif attack == 'Barrage' then
				hum.WalkSpeed = 3
			end

			animIsPlaying = true

			-- Below, hum2 is the target

			if attack == 'Barrage' then
				for i, partData in pairs(combatParts[attack]) do
					for i, combatPart in ipairs(partData) do
						combatPart.Touched:Connect(function(hit)
							local hum2 = hit.Parent:FindFirstChild('Humanoid')

							if hum2 then
								if animIsPlaying and not (hit.Parent:FindFirstChild('Torso'):FindFirstChild('Blows') or hit.Parent:FindFirstChild('Torso'):FindFirstChild('Light')) then
									for i, v in pairs(workspace.Target:GetChildren()) do
										local newV = v:Clone()

										newV.Parent = hit.Parent.Torso
										newV.Enabled = true

										barrageEffects[v.Name] = newV

										print('Added effects to target')
									end
								elseif animIsPlaying then
									barrageEffects.Blows = hit.Parent.Torso.Blows
									barrageEffects.Light = hit.Parent.Torso.Light
								end


								if attacks < 20 and animIsPlaying then
									attacks += 1

									hum2:TakeDamage(damage[attack])
								end
							end
						end)
					end
				end
			else
				task.wait(anim.Length / 2) -- Wait until the attacking body part is actually in motion
				
				for i, partData in pairs(combatParts[attack]) do
					for i, combatPart in ipairs(partData) do
						combatPart.Touched:Connect(function(hit)
							local hum2 = hit.Parent:FindFirstChild('Humanoid')

							if hum2 then
								if attacks < 1 and animIsPlaying then
									attacks += 1

									hum2:TakeDamage(damage[attack])
								end
							end
						end)
					end
				end
			end

			anim.Stopped:Wait()

			if barrageEffects.Blows then -- No need of adding "~= nil" after
				print('Destroyed barrage effects')

				barrageEffects.Blows:Destroy()
				barrageEffects.Light:Destroy()
			end

			hum.WalkSpeed = 20
			animIsPlaying = false

			task.wait(cooldown[attack])

			cooldownActive[attack] = false
			ev2:FireClient(plr, attack, cooldownActive[attack])
		end
	end
end)
1 Like

A simple solution is to replace your .Touched function with a hitbox.

The combat system would be generally better if you created hitboxes instead of using the .Touched function, and would make customizing each attack a lot easier.
You could have different hitbox shapes, sizes, offsets, etc.

Look at the hitboxes A Universal Time, and thats what im talking about.

I managed to replicate this by creating a part on the server, applying an offset to it and then use the workspace.GetPartsInPart() function.

This is my code for getting the parts in a hitbox:

function CalculateHits(Player, NewHitbox)
	local TouchingParts = workspace:GetPartsInPart(NewHitbox)
	
	--NewHitbox:GetTouchingParts()
	local HitPlayers = {}
	for i, v in pairs(TouchingParts) do
		if v.Parent ~= Player.Character and v.Parent:FindFirstChild('Humanoid') and not table.find(HitPlayers, v.Parent) then
			table.insert(HitPlayers, v.Parent)
		end
	end
	return HitPlayers
end

And my code for creating hitboxes:

local NewHitbox = Hitbox:Clone()
-- Could have used CFrame here, but i didnt for some reason.
NewHitbox.Orientation = Player.Character:WaitForChild('HumanoidRootPart').Orientation
NewHitbox.Position = (Player.Character:WaitForChild('HumanoidRootPart').Position + (Player.Character:WaitForChild('HumanoidRootPart').CFrame.LookVector * 3.5)) - Vector3.new(0, 1.5, 0)
NewHitbox.Parent = workspace

Video of the system:

Also, i would like to point out:

  1. Animations can be loaded and played on a local script, and will replicate to the server.

  2. DO NOT reload the animation whenever you play it, instead you want to load the animation once and play it whenever needed.

-- Loop through your animations and load them once, and add them to a table
Animations = {}
for i, v in pairs(script.Animations:GetChildren()) do
	Animations[v.Name] = hum.Animator:LoadAnimation(v)
end
Animations[attack]:Play()

The reason i suggest you do this is because the animator has a limit of 256 animation tracks loaded at once, so once you so 256 attacks, the animations will no longer play, and you will get an error.

3 Likes

Edit:

It works now, but just works the same. The punch still gives the effects.

--//Variables
local char = script.Parent
local hum = char:WaitForChild('Humanoid')
local ev = char.Attack
local ev2 = char.OnCooldown

--//Controls
local animIsPlaying = false

--//Tables
local combatParts = {
	Punch = {char:WaitForChild('Right Arm')},
	Uppercut = {char:WaitForChild('Left Arm')},
	Kick = {char:WaitForChild('Right Leg')},
	Barrage = {char:WaitForChild('Right Arm'), char:WaitForChild('Left Arm')}
}

local damage = {
	Punch = 10,
	Uppercut = 15,
	Kick = 22,
	Barrage = 3 -- Per hit
}

local cooldown = {
	Punch = 0.5,
	Uppercut = 3,
	Kick = 5,
	Barrage = 10
}

local cooldownActive = {
	Punch = false,
	Uppercut = false,
	Kick = false,
	Barrage = false
}

--//Functions
ev.OnServerEvent:Connect(function(plr, attack)
	if not animIsPlaying then
		local anim = hum.Animator:LoadAnimation(script[attack])
		local attacks = 0
		local barrageEffects = {
			Blows = nil,
			Light = nil
		}

		if not cooldownActive[attack] then
			anim.Priority = Enum.AnimationPriority.Action
			anim:Play()

			print('Attack: '.. tostring(attack))

			cooldownActive[attack] = true
			ev2:FireClient(plr, attack, cooldownActive[attack])

			-- Below is just speeds for specific attacks

			if attack == 'Kick' then
				hum.WalkSpeed = 0
			elseif attack == 'Barrage' then
				hum.WalkSpeed = 3
			end

			animIsPlaying = true

			-- Below, hum2 is the target

			if attack == 'Barrage' then
				for i, combatPart in pairs(combatParts[attack]) do
					combatPart.Touched:Connect(function(hit)
						local hum2 = hit.Parent:FindFirstChild('Humanoid')

						if hum2 then
							if animIsPlaying and not (hit.Parent:FindFirstChild('Torso'):FindFirstChild('Blows') or hit.Parent:FindFirstChild('Torso'):FindFirstChild('Light')) then
								for i, v in pairs(workspace.Target:GetChildren()) do
									local newV = v:Clone()

									newV.Parent = hit.Parent.Torso
									newV.Enabled = true

									barrageEffects[v.Name] = newV

									print('Added effects to target')
								end
							elseif animIsPlaying then
								barrageEffects.Blows = hit.Parent.Torso.Blows
								barrageEffects.Light = hit.Parent.Torso.Light
							end


							if attacks < 10 and animIsPlaying then
								attacks += 1

								hum2:TakeDamage(damage[attack])
							end
						end
					end)
				end
			else
				task.wait(anim.Length / 2) -- Wait until the attacking body part is actually in motion
				
				for i, combatPart in pairs(combatParts[attack]) do
					combatPart.Touched:Connect(function(hit)
						local hum2 = hit.Parent:FindFirstChild('Humanoid')

						if hum2 then
							if attacks < 1 and animIsPlaying then
								attacks += 1

								hum2:TakeDamage(damage[attack])
							end
						end
					end)
				end
			end

			anim.Stopped:Wait()

			if barrageEffects.Blows then -- No need of adding '~= nil' after
				print('Destroyed barrage effects')

				barrageEffects.Blows:Destroy()
				barrageEffects.Light:Destroy()
			end

			hum.WalkSpeed = 20
			animIsPlaying = false

			task.wait(cooldown[attack])

			cooldownActive[attack] = false
			ev2:FireClient(plr, attack, cooldownActive[attack])
		end
	end
end)