Hey! I’ve decided to make a buffer system as one of the common mistakes people new to combat systems make is not having a input buffer! This makes your game feel way more responsive and makes it feel way less like the game is against the player.
Keep in mind that this is my FIRST community resource so please do not be too harsh on me, however do give feedback please! I’ll try to fix any bugs you find.
All the documentation and everything you need is inside the module, if you need help with anything ask me!
Here’s the module!
https://create.roblox.com/store/asset/96014038264759/LoveBuffer
You should use this module INSTEAD of user input service! And if you like using ContextActionService, then unfortunately you can’t use that with this module currently ![]()
Update: I’ve now changed the module to work somewhat like ContextActionService. You register keys into the key registry so the module listens to the keys you register and does the callback with returning what key was fired.
If you want to look into the module without actually putting it in your game yet then here you go
local lb = {}
lb.__index = lb
local userinputservice = game:GetService("UserInputService") -- yeahhhh
local runService = game:GetService("RunService")
local Signal = require(script.Signal) -- im using this for the callback
--[[
__ ____ ________
/ / ____ _ _____ / __ )__ __/ __/ __/__ _____
/ / / __ \ | / / _ \/ __ / / / / /_/ /_/ _ \/ ___/
/ /___/ /_/ / |/ / __/ /_/ / /_/ / __/ __/ __/ /
/_____/\____/|___/\___/_____/\__,_/_/ /_/ \___/_/
DO
NOT
MAKE
MULTIPLE
BUFFERS
PLEASE
- JUST MAKE ONE BUFFER PER PLAYER PLEASE!! YOU DON'T NEED TO MAKE A NEW ONE EVERY TIME THEY DIE!! IT'S UNNECESSARY MEMORY LEAKS!!
- Buffers inputs yada yada yada you get the deal elden ring has it etc it makes ur game feel more responsive and allat
- inputCallback is your main guy you should use that instead of contextactionservice this module basically replaces your contextactionservice while adding buffer to it
- if you ATTEMPT to run this on the server I will HUNT YOU DOWN IRL!!!!
--]]
local BUFFER_SETTINGS = {
Buffer_Decay = .25, --[[ basically how long inputs stay in the input buffer before they get deleted, if you set this to 0 then it is infinite but
if someone spams attacks it'll have them repeating them for a long time ]]
}
function lb.new()
local self = {}
self.inputCallback = Signal.new()
self.bufferStack = {}
self.registry = {}
--[[ BUFFER MODE ]]--
-- 1 is the default, basically 1 is where you set bufferPause through the -**- function to true and while bufferPause is true it'll make callbacks wait until bufferPause is false
-- 2 is the second, it's where you manually set different keys to on or off and it checks if any keys are set to on and while any key is set to on it makes callbacks wait until no keys
-- are set to on
-- honestly i reccomend 1 as the way i used it in my games is i usually used like a using attack value somewhere and i'd set the buffer's bufferPause to the usingAttack value
-- therefor making it automatically buffer yeah yeah yeah but ok ima stop yapping ok
self.bufferMode = 1
-- mode 1 variable
self.bufferPause = false
-- mode 2 variable
self.activeKey = nil
--[[ main stuff ]]--
-- stack continuer
runService.Heartbeat:Connect(function()
local canContinue = false
if self.bufferMode == 1 then
canContinue = not self.bufferPause
elseif self.bufferMode == 2 then
canContinue = self.activeKey == nil
end
if canContinue then
if #self.bufferStack > 0 then
self.inputCallback:Fire(self.bufferStack[1].input)
table.remove(self.bufferStack, 1)
end
end
end)
local function addtostack(input)
local stackEntry = {input = input} -- i have to wrap these so they're differentiated in memory
table.insert(self.bufferStack, stackEntry)
if BUFFER_SETTINGS.Buffer_Decay ~= 0 then
task.delay(BUFFER_SETTINGS.Buffer_Decay, function()
for i, entry in ipairs(self.bufferStack) do
if entry == stackEntry then
table.remove(self.bufferStack, i)
break
end
end
end)
end
end
-- stack adder
userinputservice.InputBegan:Connect(function(i,g)
if g then return end
if self.registry[i.KeyCode.Name] ~= nil or self.registry[i.UserInputType.Name] ~= nil then
addtostack(i)
end
end)
return setmetatable(self, lb)
end
--[[ REGISTER KEY ]]--
-- this registers a key and makes the buffer listen to the actual key!
function lb:registerKey(input:InputObject)
local iName = input.Name
if self.registry[iName] then
warn("key is already registered!")
return
end
self.registry[iName] = input
end
--[[ UNREGISTER KEY ]]--
function lb:unregisterKey(input : InputObject)
local iName = input.Name
if not self.registry[iName] then
warn("input not found in registry!")
return
end
self.registry[iName] = nil
end
--[[ BUFFER PAUSE ]]--
-- use this with mode 1 only
function lb:setpause(v)
self.bufferPause = v
end
--[[ KEY ]]--
-- use this with mode 2 only
function lb:setactivekey(v)
self.activeKey = v
end
return lb
Also here’s the testing script I used for testing the buffer:
-- make a new buffer
local lb = require(game:GetService("ReplicatedStorage"):WaitForChild("LoveBuffer")).new()
-- register our keys
lb:registerKey(Enum.KeyCode.E)
-- our main callback that we will use INSTAED OF USERINPUTSERVICE OR CONTEXTACTIONSERVICE
lb.inputCallback:Connect(function(input : InputObject)
if input.KeyCode == Enum.KeyCode.E then
print("E was pressed!")
lb:setpause(true)
task.spawn(function()
task.wait(0.65)
print("press now to see if buffer works")
end)
task.wait(1)
lb:setpause(false)
end
end)