Input Buffer how to store and read inputs?

Hello, I’m trying to make an input buffer the issue is I don’t know how to make one haha so it has been quite a process luckily though there are a few good articles that I found that give some insight into how to make one. The one I hyperlinked is what I’m currently using and I’m having difficulties being able to translate what is being said to actual code.

The first part of the article basically talks about how you should map actions to numbers instead of actions to buttons as it makes things easier in the long run and I managed to get this part done using the bit32 functions (had to dig a bit to find out this existed)

Edit: for anyone that might be intimidated by the code below it’s basically just Up = 4, Down = 2, Right = 8, etc and when a key is pressed the number is added to a variable which in this case is self.inputs and I can then use this to check what buttons are pressed if self.inputs is 12 I know Up + Right is being pressed since 4 + 8 is 12 and then when a key is released the number is subtracted.

Enums.InputButtons = {
	Neutral_Input = bit32.lshift(1, 18),
	None = 0,
	Down_Direction = bit32.lshift(1, 0),
	Left_Direction = bit32.lshift(1, 1),
	Up_Direction = bit32.lshift(1, 2),
	Right_Direction = bit32.lshift(1, 3),
	DownLeft_Direction = bit32.bor(bit32.lshift(1, 0), bit32.lshift(1, 1)),
	DownRight_Direction = bit32.bor(bit32.lshift(1, 0), bit32.lshift(1, 3)),
	UpLeft_Direction = bit32.bor(bit32.lshift(1, 2), bit32.lshift(1, 1)),
	UpRight_Direction = bit32.bor(bit32.lshift(1, 2), bit32.lshift(1, 3)),
	TaptoHoldButtonShift = 19,
	HeldDown_Direction = bit32.lshift(bit32.lshift(1, 0), 19),
	Guard_Button = bit32.lshift(1, 4),
	Punch_Button = bit32.lshift(1, 5),
	Kick_Button = bit32.lshift(1, 6),
	Tech_Button = bit32.lshift(1, 7),
	Trigger_Button = bit32.lshift(1, 8),
	Selection_Button = bit32.lshift(1, 9),
	Cancel_Button = bit32.lshift(1, 10),
	Modifier_Button = bit32.lshift(1, 11),
	Menu_Pause_Button = bit32.lshift(1, 12),
}

And then this is my input module where you can see how the above code gets used and it works quite well.

function Input.new()
	local self = setmetatable({},Input)

	self.buffer = InputBuffer.new()
	self.inputs = 0
	self.keybinds = {
		["Left"] = Enum.KeyCode.A,
		["Right"] = Enum.KeyCode.D,
		["Up"] = Enum.KeyCode.W,
		["Down"] = Enum.KeyCode.S,
		["LightAttack"] = Enum.KeyCode.H,
	}	
	self.keymap = {
		[self.keybinds["Left"]] = inputButtons.Left_Direction,
		[self.keybinds["Right"]] = inputButtons.Right_Direction,
		[self.keybinds["Up"]] = inputButtons.Up_Direction,
		[self.keybinds["Down"]] = inputButtons.Down_Direction,
		[self.keybinds["LightAttack"]] = inputButtons.Punch_Button,
	}

	UserInputService.InputBegan:Connect(function(inputObject, gameProcessed)
		self:inputBegan(inputObject, gameProcessed)
	end)

	UserInputService.InputEnded:Connect(function(inputObject, gameProcessed)
		self:inputEnded(inputObject, gameProcessed)
	end)	

	return self
end

function Input:inputBegan(inputObject, gameProcessed)
	if gameProcessed then 
		return 
	end
	
	-- don't care about anything that's not the keyboard 
	if inputObject.UserInputType ~= Enum.UserInputType.Keyboard then
		return
	end
	
	-- gonna be something like 8, 2, 4, etc
	local input = self.keymap[inputObject.KeyCode]
	
	-- set the input bit in the inputs number
	self.inputs = bit32.bor(self.inputs, input)
end

function Input:inputEnded(inputObject, gameProcessed)
	if gameProcessed then 
		return 
	end
	
	if inputObject.UserInputType ~= Enum.UserInputType.Keyboard then
		return
	end
	
	local input = self.keymap[inputObject.KeyCode]
	
	-- unset the input bit in the inputs number
	self.inputs = bit32.band(self.inputs, bit32.bnot(input))
end

The next part of the article is actually storing commands/input which is where I start to get stuck. I know I need a table or dictionary to store things, but the article talks about this being something that happens every frame (ex: Frame #1 left was pressed, Frame #2 nothing was pressed, Frame #3 left and punch was pressed, etc) and only storing inputs if they weren’t pressed before instead of continuously and I haven’t been able to figure out how to get around this.

This is the code I tried doing, but I don’t think it’s that effective.

local keysPressedLastFrame = {}
function Input:update()
	local keysPressedThisFrame = UserInputService:GetKeysPressed()
	local newKeysPressed = {}

	for index,inputObject in pairs(keysPressedThisFrame) do
		if not keysPressedLastFrame[index] then
			newKeysPressed[index] = inputObject.KeyCode
		end
	end

	keysPressedLastFrame = keysPressedThisFrame
	print("New keys pressed this frame",newKeysPressed)
end

-- In client module being ran every frame
local function processFrame(deltaTime)
	localFrame += 1
	
	input:update()
end
2 Likes