User Inputs slow [2.5D Fighting Game]

Hello everyone, I am writing to ask about “Why is UserInputService” so slow?

Context

I am making a 2.5D fighting game and currently, is trying to make a proper input system.

My approach:

  • Have a table to store translated inputs
  • Use “UserInputService” to take normal keyboard inputs and translate to the understandable inputs such as “Up, Down, Back, Forward” etc…
  • Have an internal frame-clock, and in that clock after every 18 frames, the script processes the input table to find the a sequence that is the same as the sequence in the dictionary
  • If there is no matching sequence, then clear the table, and if there is, then execute the function inside it and clear the table.

What’s the problem?

Just like the title said, the UserInputService is slow. It takes 3 frames to process one input and place it into the table, this is horrible for frame accurate inputs. How can I solve this?

Source Code:

local Player: Player = game.Players.LocalPlayer
local Character: Model = Player.Character or Player.CharacterAdded:Wait()
local HumanoidRootPart: Part = Character:WaitForChild('HumanoidRootPart')


local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Melee = require(game.ReplicatedStorage.Melee).new()

local State: StringValue = Player:WaitForChild('State')

Melee:SetKeyConfigs(Melee.DefaultKeyConfig)
Melee:SetMoveset(Melee.ExampleMoveset)

UIS.InputBegan:Connect(function(input: InputObject, gameProcessedEvent: boolean)
	if gameProcessedEvent then return end
	if input.UserInputType == Enum.UserInputType.Keyboard then
		Melee:RecordInput(input.KeyCode)
	end
end)

coroutine.resume(coroutine.create(function()
	local ForwardKeyConfig = {
		[Enum.KeyCode.H] = "Punch",
		[Enum.KeyCode.J] = "Kick",
		[Enum.KeyCode.W] = "Up",
		[Enum.KeyCode.S] = "Down",
		[Enum.KeyCode.D] = "Forward",
		[Enum.KeyCode.A] = "Back"
	}

	local BackwardKeyConfig = {
		[Enum.KeyCode.H] = "Punch",
		[Enum.KeyCode.J] = "Kick",
		[Enum.KeyCode.W] = "Up",
		[Enum.KeyCode.S] = "Down",
		[Enum.KeyCode.D] = "Back",
		[Enum.KeyCode.A] = "Forward"
	}

	RunService.Heartbeat:Connect(function()
		if Melee.GlobalFunctions.Round(HumanoidRootPart.Orientation.Y) == 90 then
			Melee:SetKeyConfigs(ForwardKeyConfig)
		else if Melee.GlobalFunctions.Round(HumanoidRootPart.Orientation.Y) == -90 then
				Melee:SetKeyConfigs(BackwardKeyConfig)
			end
		end
	end)
end))


local function ProcessInputs()
	
	local BufferBeforeFlush = Melee:GetBuffer()

	if Melee:ProcessBuffer(BufferBeforeFlush) then
		for _, moves in pairs(Melee:GetMoveset()) do
			if moves.Name == Melee:ProcessBuffer(BufferBeforeFlush) then		
				if moves.AvoidState[State.Value] then
					print("Supposed to be doing:", Melee:ProcessBuffer(BufferBeforeFlush), "But not because of:", State.Value)
					Melee:ClearBuffer()
				else
					if Player:WaitForChild('CanCombo').Value == true then
						moves.Action(Player)
						Melee:ClearBuffer()
					end
				end
			end
		end
	else
		Melee:ClearBuffer()
	end




end


while true do

	for i = 1, 18 do
		RunService.RenderStepped:Wait()
	end


	ProcessInputs()
end

Apologize for the spaghetti.

3 Likes

This section here is a bit confusing to me…

Try adding a wait or task.wait immediately after while true do and see if that solves your issue. Maybe ProcessInputs() is running much more often than it should?

Use contextaction service and bind the the keys ?

I was told it should wait every 18th frame before processing the inputs in the buffer

I’m so confused, why? That’ll just make it slower and more inaccurate?

Hi. I’m working on a “universal” fighting game framework. First off, you don’t want to use a “backward key config” and a “forward key config.” I instead advise using a series of unit vectors and compounding them together depending on the input, and then using dot products (or something of a similar fashion) to turn your inputs into an 8-way system.

This allows you to support keyboard inputs via binding the normal cardinal directions to the WASD keys and controller inputs by simply passing the joystick position (or by applying the WASD method to the D-Pad.)

Regarding your UserInputService problem, UserInputService is by no means slow. I can’t even remember any method that naturally takes more than a frame to run that isn’t explicitly mentioned in the documentation. As @Solaris_Penumbra said, that snippet is more than “a bit sketch.”
I assume that you’re waiting every 18 frames to allow for an input buffer, but that isn’t how an input buffer works as far as I know. An input buffer is just “reserve storage” for your intended action during the recovery frames of a move, without the buffer you’d be wasting plus frames casting a skill. Any time your character is currently minus, you should be able to take advantage of an input buffer within the sanity of ~8-10 frames, maybe 12. Your character is never going to be 18 frames minus every time. You’re effectively giving your player hardcoded input lag for no real reason.