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.
I’m getting an error:
Also, I’ve updated the 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")
-- 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)