What do you want to achieve? Keep it simple and clear!
So, I’ve been making a sword combat system and I keep getting a problem which I do not know how to fix.
What is the issue? Include screenshots / videos if possible!
The issue is that the first round of combos aren’t working.
What solutions have you tried so far? Did you look for solutions on the Developer Hub?
I couldn’t find any solutions about this problem.
Also, I’ve been using raycast hitbox for the sword combat system.
Server Script:
-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local StarterPack = game:GetService("StarterPack")
-- Variables
local player, character, humanoid, tool
tool = script.Parent.Parent
character = tool.Parent.Parent.Character
humanoidVar = character:WaitForChild("Humanoid")
player = Players:GetPlayerFromCharacter(character)
-- ASCS Folder
local ASCS = ReplicatedStorage.ASCS
-- Remote Events Folder
local RemoteEventsFolder = ASCS.RemoteEvents
-- Assets Folder
local AssetsFolder = ASCS.Assets
-- OtherFolders
local NPCFolder = workspace.NPCs
-- Values Folder
local GlobalValuesFolder = ASCS.Values
local ToolValuesFolder = tool.Values
-- Remote Events
local RemoteEvents = {
RemoteEventsFolder.AddCombo;
RemoteEventsFolder.ResetCombo;
RemoteEventsFolder.HitStop;
RemoteEventsFolder.HitStart;
}
-- Values
local Values = {
ToolValuesFolder:WaitForChild("CanDamage");
ToolValuesFolder:WaitForChild("Combo");
}
-- Tool Config Folder
local WeaponConfig = ASCS.ToolConfig
-- Tool
local tool = script.Parent.Parent
-- Modules
local RaycastHitboxV4 = require(ASCS.Modules.RaycastHitboxV4)
local GlobalConfig = require(ASCS.GlobalConfig.Config)
local Config = require(WeaponConfig:FindFirstChild(tool.Name))
print("Character, humanoid, tool and player is set in the variable.")
local Model = ASCS.Models:FindFirstChild(tool.Name).Handle:Clone()
Model.Parent = tool
-- Hitbox
local newHitbox = RaycastHitboxV4.new(tool:WaitForChild("Handle"))
newHitbox.RaycastParams = RaycastParams.new()
newHitbox.RaycastParams.FilterDescendantsInstances = {character}
newHitbox.RaycastParams.FilterType = Enum.RaycastFilterType.Blacklist
newHitbox.OnHit:Connect(function(hit, humanoid)
if Config.CanHitNpc and not Config.CanHitPlayer then
if NPCFolder:FindFirstChild(humanoid.Parent.Name) and humanoid.Parent ~= Players:GetPlayerFromCharacter(humanoid.Parent) then
if Values[2].Value == Config.MaxCombo then
humanoid:TakeDamage(Config.LastComboDamage)
elseif Values[2].Value ~= Config.MaxCombo then
humanoid:TakeDamage(Config.NormalDamage)
end
else
return
end
elseif not Config.CanHitNpc and Config.CanHitPlayer then
if humanoid.Parent == Players:GetPlayerFromCharacter(humanoid.Parent) then
if Values[2].Value == Config.MaxCombo then
humanoid:TakeDamage(Config.LastComboDamage)
elseif Values[2].Value ~= Config.MaxCombo then
humanoid:TakeDamage(Config.NormalDamage)
end
else
return
end
elseif not Config.CanHitNpc and not Config.CanHitPlayer or Config.CanHitNpc and Config.CanHitPlayer then
return
end
end)
RemoteEvents[4].OnServerEvent:Connect(function()
newHitbox:HitStart()
end)
RemoteEvents[3].OnServerEvent:Connect(function()
newHitbox:HitStop()
end)
RemoteEvents[1].OnServerEvent:Connect(function()
Values[2].Value += 1
end)
RemoteEvents[2].OnServerEvent:Connect(function()
Values[2].Value = 0
end)
Local Script:
-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local StarterPack = game:GetService("StarterPack")
local UserInputService = game:GetService("UserInputService")
-- Variables
local player, character, humanoid, tool
player = Players.LocalPlayer
character = player.Character or player.CharacterAdded:Wait()
tool = script.Parent.Parent
humanoid = character:WaitForChild("Humanoid")
-- ASCS Folder
local ASCS = ReplicatedStorage.ASCS
-- Remote Events Folder
local RemoteEventsFolder = ASCS.RemoteEvents
-- Assets Folder
local AssetsFolder = ASCS.Assets
-- Remote Events
local RemoteEvents = {
RemoteEventsFolder.AddCombo;
RemoteEventsFolder.ResetCombo;
RemoteEventsFolder.HitStop;
RemoteEventsFolder.HitStart;
}
-- Values Folder
local ToolValuesFolder = tool.Values
local GlobalValuesFolder = ASCS.Values
-- Values
local Values = {
ToolValuesFolder:WaitForChild("CanDamage");
ToolValuesFolder:WaitForChild("Combo");
}
-- Tool
local tool = script.Parent.Parent
-- Modules
local RaycastHitboxV4 = require(ASCS.Modules.RaycastHitboxV4)
local GlobalConfig = require(ASCS.GlobalConfig.Config)
local WeaponConfig = require(ASCS.ToolConfig:FindFirstChild(tool.Name))
print("Character, humanoid, tool and player is set in the variable.")
tool.Equipped:Connect(function()
Values[1].Value = false
local EquipTrack = humanoid:LoadAnimation(tool.Animations.Equip)
EquipTrack:Play()
wait(0.5)
Values[1].Value = true
end)
tool.Unequipped:Connect(function()
Values[1].Value = false
local EquipTrack = humanoid:LoadAnimation(tool.Animations.UnEquip)
EquipTrack:Play()
end)
local function Attack()
local AttackAnim = humanoid:LoadAnimation(tool.ComboAnimations:WaitForChild("Combo" .. tostring(Values[2].Value)))
AttackAnim:Play()
humanoid.WalkSpeed -= WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower -= WeaponConfig.JumpPowerDecrease
-- Enabling hitbox
RemoteEvents[4]:FireServer()
task.wait(AttackAnim.Length)
RemoteEvents[3]:FireServer()
humanoid.WalkSpeed += WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower += WeaponConfig.JumpPowerDecrease
end
local Debounce = false
UserInputService.InputBegan:Connect(function(input, gameProccessed)
if input.UserInputType == Enum.UserInputType.MouseButton1 and player.Character:FindFirstChild(tool.Name) then
if Debounce == false and Values[1].Value == true then
Debounce = true
if Values[2].Value >= WeaponConfig.MaxCombo then
RemoteEvents[2]:FireServer()
end
Attack()
RemoteEvents[1]:FireServer()
task.wait(WeaponConfig.HitCooldown)
Debounce = false
end
end
end)
Now I’ll show you what I mean by the first round of combos aren’t working…
Also, I got an other problem too, which is that there isn’t any cooldown on the first round of combos.
If it is 0 then the hitbox will be instantly cancelled.
local function Attack()
local AttackAnim = humanoid:LoadAnimation(tool.ComboAnimations:WaitForChild("Combo" .. tostring(Values[2].Value)))
AttackAnim:Play()
humanoid.WalkSpeed -= WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower -= WeaponConfig.JumpPowerDecrease
-- Enabling hitbox
RemoteEvents[4]:FireServer()
print(AttackAnim.Length) --I'm guessing this length is 0 as animations are still loading
--print to see if its true my first suspicion
task.wait(AttackAnim.Length)
RemoteEvents[3]:FireServer()
humanoid.WalkSpeed += WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower += WeaponConfig.JumpPowerDecrease
end
You probably should load all the animations and then put them in a table from 1,2,3,4, and then :Play()
You shouldn’t load the animations every time you attack. Only once when you initialize the script.
Edit: NVM it seems like animation tracks get automatically removed. Seems like you could also try preloading all the combo animations initially at the top of the script.
-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local StarterPack = game:GetService("StarterPack")
local UserInputService = game:GetService("UserInputService")
-- Variables
local player, character, humanoid, tool
player = Players.LocalPlayer
character = player.Character or player.CharacterAdded:Wait()
tool = script.Parent.Parent
humanoid = character:WaitForChild("Humanoid")
-- Mouse
local Mouse = player:GetMouse()
local MouseIcon = Mouse.Icon
-- ASCS Folder
local ASCS = ReplicatedStorage.ASCS
-- Remote Events Folder
local RemoteEventsFolder = ASCS.RemoteEvents
-- Assets Folder
local AssetsFolder = ASCS.Assets
-- Remote Events
local RemoteEvents = {
RemoteEventsFolder.AddCombo;
RemoteEventsFolder.ResetCombo;
RemoteEventsFolder.HitStop;
RemoteEventsFolder.HitStart;
}
-- Values Folder
local ToolValuesFolder = tool.Values
local GlobalValuesFolder = ASCS.Values
-- Values
local Values = {
ToolValuesFolder:WaitForChild("CanDamage");
ToolValuesFolder:WaitForChild("Combo");
}
-- Tool
local tool = script.Parent.Parent
-- Modules
local RaycastHitboxV4 = require(ASCS.Modules.RaycastHitboxV4)
local GlobalConfig = require(ASCS.GlobalConfig.Config)
local WeaponConfig = require(ASCS.ToolConfig:FindFirstChild(tool.Name))
print("Character, humanoid, tool and player is set in the variable.")
tool.Equipped:Connect(function()
Mouse.Icon = AssetsFolder.CrosshairId.Value
Values[1].Value = false
local EquipTrack = tool.Animations:WaitForChild("Equip")
EquipTrack:Play()
wait(0.5)
Values[1].Value = true
end)
tool.Unequipped:Connect(function()
Mouse.Icon = MouseIcon
Values[1].Value = false
local EquipTrack = tool.Animations:WaitForChild("UnEquip")
EquipTrack:Play()
end)
local function Attack()
local AttackAnim = tool.ComboAnimations:WaitForChild("Combo"..tostring(Values[2].Value))
AttackAnim:Play()
humanoid.WalkSpeed -= WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower -= WeaponConfig.JumpPowerDecrease
-- Enabling hitbox
RemoteEvents[4]:FireServer()
task.wait(AttackAnim.Length)
RemoteEvents[3]:FireServer()
humanoid.WalkSpeed += WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower += WeaponConfig.JumpPowerDecrease
end
local Debounce = false
UserInputService.InputBegan:Connect(function(input, gameProccessed)
if input.UserInputType == Enum.UserInputType.MouseButton1 and player.Character:FindFirstChild(tool.Name) then
if Debounce == false and Values[1].Value == true then
Debounce = true
if Values[2].Value >= WeaponConfig.MaxCombo then
RemoteEvents[2]:FireServer()
end
Attack()
RemoteEvents[1]:FireServer()
task.wait(WeaponConfig.HitCooldown)
Debounce = false
end
end
end)
Instance Creator Script:
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ContentProvider = game:GetService("ContentProvider")
-- Tool
local tool = script.Parent.Parent
-- Modules
local WeaponConfig = require(ReplicatedStorage.ASCS.ToolConfig:FindFirstChild(tool.Name))
for i, v in pairs(WeaponConfig.ComboAnimations) do
local Animation = Instance.new("Animation", tool.ComboAnimations)
Animation.Name = i
Animation.AnimationId = v
ContentProvider:PreloadAsync({Animation})
end
for i, v in pairs(WeaponConfig.Animations) do
local Animation = Instance.new("Animation", tool.Animations)
Animation.Name = i
Animation.AnimationId = v
ContentProvider:PreloadAsync({Animation})
end
local anims = {
AnimationsFolder:WaitForChild("Swing1"), --Animation instances or your animation ids
AnimationsFolder:WaitForChild("Swing2"),
AnimationsFolder:WaitForChild("Swing3"),
}
for index,animation in ipairs(anims) do--ipairs because its an array
anims[index] = animator:LoadAnimation(animation) -- replace animation with animation track
end
local function Attack()
local AttackAnim = anims[tostring(Values[2].Value)]
repeat
warn("Animations haven't loaded yet")
task.wait()
until AttackAnim.Length > 0
AttackAnim:Play()
humanoid.WalkSpeed -= WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower -= WeaponConfig.JumpPowerDecrease
-- Enabling hitbox
RemoteEvents[4]:FireServer()
task.wait(AttackAnim.Length)
RemoteEvents[3]:FireServer()
humanoid.WalkSpeed += WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower += WeaponConfig.JumpPowerDecrease
end
-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local StarterPack = game:GetService("StarterPack")
local UserInputService = game:GetService("UserInputService")
-- Variables
local player, character, humanoid, tool
player = Players.LocalPlayer
character = player.Character or player.CharacterAdded:Wait()
tool = script.Parent.Parent
humanoid = character:WaitForChild("Humanoid")
-- Mouse
local Mouse = player:GetMouse()
local MouseIcon = Mouse.Icon
-- ASCS Folder
local ASCS = ReplicatedStorage.ASCS
-- Remote Events Folder
local RemoteEventsFolder = ASCS.RemoteEvents
-- Assets Folder
local AssetsFolder = ASCS.Assets
-- Remote Events
local RemoteEvents = {
RemoteEventsFolder.AddCombo;
RemoteEventsFolder.ResetCombo;
RemoteEventsFolder.HitStop;
RemoteEventsFolder.HitStart;
}
-- Values Folder
local ToolValuesFolder = tool.Values
local GlobalValuesFolder = ASCS.Values
-- Values
local Values = {
ToolValuesFolder:WaitForChild("CanDamage");
ToolValuesFolder:WaitForChild("Combo");
}
-- Tool
local tool = script.Parent.Parent
-- Modules
local RaycastHitboxV4 = require(ASCS.Modules.RaycastHitboxV4)
local GlobalConfig = require(ASCS.GlobalConfig.Config)
local WeaponConfig = require(ASCS.ToolConfig:FindFirstChild(tool.Name))
-- Animations
local ComboAnims = tool.ComboAnimations:GetChildren()
for index,animation in ipairs(ComboAnims) do--ipairs because its an array
ComboAnims = humanoid.Animator:LoadAnimation(animation) -- replace animation with animation track
end
local function Attack()
local AttackAnim = tool.ComboAnimations:WaitForChild("Combo"..tostring(Values[2].Value))
repeat
warn("Animations haven't loaded yet")
task.wait()
until AttackAnim.Length > 0
AttackAnim:Play()
humanoid.WalkSpeed -= WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower -= WeaponConfig.JumpPowerDecrease
-- Enabling hitbox
RemoteEvents[4]:FireServer()
task.wait(AttackAnim.Length)
RemoteEvents[3]:FireServer()
humanoid.WalkSpeed += WeaponConfig.WalkSpeedDecrease
humanoid.JumpPower += WeaponConfig.JumpPowerDecrease
end
print("Character, humanoid, tool and player is set in the variable.")
tool.Equipped:Connect(function()
Mouse.Icon = AssetsFolder.CrosshairId.Value
Values[1].Value = false
local EquipTrack = humanoid:WaitForChild("Animator"):LoadAnimation(tool.Animations:WaitForChild("Equip"))
EquipTrack:Play()
wait(0.5)
Values[1].Value = true
end)
tool.Unequipped:Connect(function()
Mouse.Icon = MouseIcon
Values[1].Value = false
local EquipTrack = humanoid:WaitForChild("Animator"):LoadAnimation(tool.Animations:WaitForChild("UnEquip"))
EquipTrack:Play()
end)
local Debounce = false
UserInputService.InputBegan:Connect(function(input, gameProccessed)
if input.UserInputType == Enum.UserInputType.MouseButton1 and player.Character:FindFirstChild(tool.Name) then
if Debounce == false and Values[1].Value == true then
Debounce = true
if Values[2].Value >= WeaponConfig.MaxCombo then
RemoteEvents[2]:FireServer()
end
Attack()
RemoteEvents[1]:FireServer()
task.wait(WeaponConfig.HitCooldown)
Debounce = false
end
end
end)