Problems with trigger input detection

I have been using InputChanged in order to process input from the left and right trigger buttons used for the throttle and brake system on my vehicle chassis. The problem however is that i get extremely inaccurate readings when the input is used rapidly (or sometimes not even that quickly). If you tap the trigger, for example, for about 0.5s it might read .4 and then not register anything else after (unless you start fiddling with it again). Is there a better way to detect input or could there be some way to constantly poll the input value?

1 Like

You can listen to InputBegan, and then keep a reference to the inputObject that you get back. That inputObject will keep updating until InputEnded is called with that inputObject.

4 Likes

Ok, sounds nice but, is the problem with InputChanged that it stinks at detecting change or is it a problem with the way roblox reads the controller input? Also does it fire with InputBegan too? I thought it only fired on InputChanged.

Also does that mean I can just do something like this?

local controllerGas,controllerBrake
--on input began
--ButtonR2
controllerGas = inputobject
--ButtonL2
controllerBrake = inputobject

--on input ended (to reset the values)
--ButtonR2
controllerGas = nil
--ButtonL2
controllerBrake = nil

--later code
if usingController then
    throttle = xboxthrottle() --from controller input objects (using Position)
else
    throttle = pcthrottle() --from keyboard input
end

I’m not sure, it could be a variety of issues, i.e. it might also be something about your controller. I would test with some other tool that shows you input values and see if that has the same issue. If not, it might be a bug with Roblox.

Yes that pseudo seems about right.

No it is not with my controller. It works perfectly fine on steam and console games. This bug also happens for other people.

Would you mind testing it if you have a controller? I implemented what you suggested

I checked it out in Studio.

Not seeing this. The values it spits out seem very accurate to me, and I can use the whole 0-1 range. No matter if it’s a fast or slow input.

It does seem like InputBegan will only fire once you hold the trigger down fully, i.e.:

  0, 0, 0.0509964302
  0, 0, 0.188238174
  0, 0, 0.211767942
  0, 0, 0.494125187
  0, 0, 0.603930771
  0, 0, 0.894131303
InputBegan  Enum.KeyCode.ButtonR2
  0, 0, 1
  0, 0, 0.760795951
  0, 0, 0.219611198
  0, 0, 0.0196234025
  0, 0, 0
InputEnded

So you might want to skip the whole InputBegan/InputEnded thing I mentioned earlier and just listen for InputChanged, then just update some variables so that you can use the values elsewhere in your code.

Yes but for some odd reason if i tap it it says ButtonR2 0.5 then it doesnt say 0
It happens to everyone else in my game
Will it have any problems if i bind stuff to the runservice

Play this game with your controller
Chassis test
Try for example revving in neutral. You can see the issue.
People have said it works in AC6 chassis and i checked. They also use InputChanged. I have no idea whats wrong.
I also have 2 functions bound to InputChanged

Most of my code:

uis.InputChanged:Connect(function(io)
    if isGamepad(io) then
	    --print(io.KeyCode.Name,io.Position)
	    if io.KeyCode.Name=="Thumbstick1" then
	    	-- data assigned to gamepadSteer
	    elseif io.KeyCode.Name=="ButtonR2" then
	    	--data assigned to trig1
	    	gamepadThrottle = trig1-trig2
	    elseif io.KeyCode.Name=="ButtonL2" then
	    	--data assigned to trig2
	    	gamepadThrottle = trig1-trig2
	    end
    end
end)

where isGamepad is just

local isGamepad = function(input)
	local v = input.UserInputType.Value
	return v>=12 and v<=19
end

You won’t get the 0 value if you just connect to InputChanged. The 0 values fires on InputEnded. Similarly, the 1 value (fully down) only fires on InputBegan.

You should do this:

local triggers = {
	[Enum.KeyCode.ButtonL2] = 0;
	[Enum.KeyCode.ButtonR2] = 0;
}

local gamepadThrottle = 0

local function inputChanged(inputObject)
	if triggers[inputObject.KeyCode] then
		triggers[inputObject.KeyCode] = inputObject.Position.Z
		gamepadThrottle = triggers[Enum.KeyCode.ButtonR2] - triggers[Enum.KeyCode.ButtonL2]
	end
end

game:GetService("UserInputService").InputBegan:Connect(inputChanged) -- x = 1 values
game:GetService("UserInputService").InputChanged:Connect(inputChanged) -- 0 < x < 1 values
game:GetService("UserInputService").InputEnded:Connect(inputChanged) -- x = 0 values

-- (...) -- whatever other code goes here

-- Just a bit of code to show the value:
while wait() do
	print(gamepadThrottle)
end

A few other (off-topic) notes on your general coding style based on the sample you replied with:

  • Don’t do io.KeyCode.Name=="ButtonR2" for checking against an enum item. The proper way to write this check is: io.KeyCode == Enum.KeyCode.ButtonR2.
  • Try not to use the numerical values of enum items to determine what to do. The values are abstracted away on purpose. Don’t write v>=12 and v<19, 12 and 19 are magic numbers here that are not future-proof and obfuscate what you are actually checking for.
  • Besides, you don’t need to check if the input type is a controller. If it’s a trigger, it should rev/brake, so all you need is the keycode check. (whether it’s a gamepad or not is usually implied by the fact that it has a trigger, even)
2 Likes

Whats wrong with checking the name though and is it ok to use gamepad1.value and gamepad9.value instead or check if name contains Gamepad? I use it for other checks. Also does that mean i don’t need a trigger deadzone?

TYSM works beautifully in-game. Shame i cant post it in showcases yet tho