Making a combo system

I’m creating a beat 'em up game, like streets of rage, castle crashers, etc. I want to make a combo attack, just like these games commonly have.

To define a combo attack: When the player attacks, and hits a target, they have a certain window of time to attack again, doing a different attack, and then once more with the same amount of time, for a final attack, also different from the previous two. If the player doesn’t attack in that window of time, the combo is reset, and next time they attack, it’ll do the first attack again.

If anyone can give me some tips on how I would implement this, I’d appreciate it greatly.

You should keep a counter going for which combo index the last attack was. So if the last attack in the combo was the second one, then the last index is 2 and the current one is therefore 2 + 1 = 3.

You also want to keep track of the time the last attack was initiated at.

Now, when a new attack is made, you check if the time passed since the last attack is more than the time window or not.

local isInTimeWindow = time() - lastAttackTime < windowLength

If the attack was in the window, increment the combo index by one and start the according attack.

Otherwise, if it wasn’t in the window, reset the combo index to 1 and go on from there.

Additionally, since I presume the combo isn’t infinite, you might want to reset the combo index to 1 even if the attack was in the time window, but the combo index exeeded the combo length

if you only have the window of attack requirement then,

local comboConfigs = {
  { Animation = "...", WindowStart = 0.5, WindowDuration = 1.0 },
  { Animation = "...", WindowStart = 0.5, WindowDuration = 1.0 },
  { Animation = "...", Cooldown = 2.0 },
}
local combo = 1
local canAttack = true
local comboThread = nil
attackButton.Activated:Connect(function()
  if not canAttack then return end

  if comboThread then -- we are within the previous combo input window
    task.cancel(comboThread)
    comboThread = nil
  end

  local comboConfig = comboConfigs[combo]
  -- do the comboConfig.Animation, and generate hitbox etc.
  task.spawn(function() DoComboAttack(comboConfig) end)

  canAttack = false
  combo += 1

  if comboConfig.WindowStart then -- will have more combo
    comboThread = task.delay(comboConfig.WindowStart, function()
      canAttack = true -- allow next combo input
      task.wait(comboConfig.WindowDuration)
      combo = 1 -- reset combo if window is over
      comboThread = nil
    end)

  else -- finished final move
    task.wait(comboConfig.Cooldown)
    canAttack = true
    combo = 1
  end
end)