Hello Everyone, What is the best way to create a fighting game 2D input buffer?
I’ve already attempted making one which looks like this
-- Constant Variables
local Player: Player = game.Players.LocalPlayer
local Character: Model = Player.Character or Player.CharacterAdded:Wait()
local Humanoid: Humanoid = Character:WaitForChild('Humanoid')
local HumanoidRootPart: Part = Character:WaitForChild('HumanoidRootPart')
local Metadata: Folder = Player:WaitForChild('Metadata')
local StateValue: StringValue = Metadata:WaitForChild('State')
local Animator: Animator
-- Prequisites.
if Humanoid:FindFirstChild("Animator") then
Animator = Humanoid:FindFirstChild("Animator")
else
Animator = Instance.new('Animator', Humanoid)
end
-- Test Dataset
local moveSet = {
["1"] = {
["Initial"] = {
['Animation'] = '14465067787',
['VelocityForwards'] = 1,
['DirectionAhead'] = 2.5,
['HitboxSize'] = Vector3.new(5,5,5),
['KnockBackForce'] = 500 -- Keep relatively small like around 1000
},
["23"] = "Right Hook",
["32"] = "Kick",
["11"] = "Headbutt",
["22"] = "DoublePunch"
},
['2'] = {
},
['3'] = {
}
}
-- Requires
local Polarix = require(game:GetService("ReplicatedStorage").Polarix).new()
local Keyboard = require(game:GetService("ReplicatedStorage").Polarix.Modules.Util.Keyboard).new()
local Trove = require(game:GetService("ReplicatedStorage").Polarix.Modules.Util.Trove).new()
local Boost = require(game:GetService("ReplicatedStorage").Polarix.Modules.Global.Boost)
-- Runtime Variables
local inputTable = {}
local lastInputTime = 0
local comboString = ""
local comboMatch
local canAttack = false
-- Function to translate keybinds to universal numeric inputs
local function TranslateKeyCode(input)
local keyReturnTable = {
[Enum.KeyCode.H] = "1",
[Enum.KeyCode.J] = "2",
[Enum.KeyCode.K] = "3"
}
return keyReturnTable[input]
end
-- Function to clear inputTable if no inputs within the last 3 seconds
local function ClearInputTableIfIdle()
if tick() - lastInputTime > 0.3 then
inputTable = {}
end
end
-- Function to get an animationTrack to be playable via Animator.
-- Parameters: ID
-- Returns: AnimationTrack
local function getPlayableAnimation(animationId: string)
local AnimationToPlay = Instance.new('Animation')
AnimationToPlay.AnimationId = "rbxassetid://"..animationId
local PlayableAnimation = Animator:LoadAnimation(AnimationToPlay)
Trove:Add(PlayableAnimation)
Trove:Add(AnimationToPlay)
return PlayableAnimation
end
-- Main Code Execution
Keyboard.KeyDown:Connect(function(key)
local numericInput = TranslateKeyCode(key)
if numericInput then
lastInputTime = tick() -- Update last input time
table.insert(inputTable, numericInput)
comboString = tostring(table.concat(inputTable))
print("ComboString:", comboString)
local lastIndex = string.len(comboString) - 1
local lastChar = string.sub(comboString, lastIndex, lastIndex)
local secondLastChar = string.sub(comboString, lastIndex - 1, lastIndex - 1)..lastChar
local thirdLastChar = secondLastChar..string.sub(comboString, lastIndex - 2, lastIndex - 2)
print("LastCharacter:", lastChar)
print("SecondLastCharacter:", secondLastChar)
print("ThirdLastCharacter:", thirdLastChar)
print("CurrentPlayerState:", StateValue.Value)
if StateValue.Value ~= "ForwardDash" or StateValue.Value ~= "BackwardDash" then
if lastChar == "" then
local Data:{} = moveSet[numericInput]["Initial"]
local AnimationId: string = Data.Animation
local Velocity: number = Data.VelocityForwards
local DirectionAhead: number = Data.DirectionAhead
local HitboxSize: Vector3 = Data.HitboxSize
local KnockBackForce: number = Data.KnockBackForce
local AnimationToPlay = Instance.new('Animation')
AnimationToPlay.AnimationId = "rbxassetid://"..AnimationId
local PlayableAnimation = Animator:LoadAnimation(AnimationToPlay)
Trove:Add(PlayableAnimation)
Trove:Add(AnimationToPlay)
PlayableAnimation.KeyframeReached:Connect(function(keyframeName: string)
print(keyframeName)
if keyframeName == "RegisterHit" then
Boost.AddVelocity(HumanoidRootPart, 600, 0.1)
Polarix:FireMultiplePackets("CreateInputHitbox", {HumanoidRootPart, DirectionAhead, HitboxSize, KnockBackForce})
end
end)
PlayableAnimation:Play()
Trove:Connect(PlayableAnimation.Stopped, function()
Trove:Clean()
end)
end
if string.len(comboString) >= 3 then
if moveSet[numericInput][secondLastChar] then
print(moveSet[numericInput][secondLastChar])
end
end
end
end
end)
-- Connect a timer to periodically check and clear inputTable if idle
local checkIdleTimer = game:GetService("RunService").Heartbeat:Connect(ClearInputTableIfIdle)
As you can tell it’s pretty janky and pretty flawed, If anyone can tell me any methods, structures, or preferably articles I can take a look at, it would be much appreciated!