Clarify is_action_pressed() for multiple assigned buttons#30890
Conversation
|
Would it be better to change the implementation of |
It would make such behavior in alignment according to my previous observations in other PR #30792 (comment). If people want the behavior described here, they could use |
|
I'll merge this for now as it properly describes the current behavior. Might be worth opening an issue to further discuss @bojidar-bg's proposal. |
|
Thanks! |
|
For anyone that reaches here and want this Add this to an AutoLoad static func is_pressed(action):
var is_pressed = false
for event in InputMap.get_action_list(action):
if event is InputEventKey:
is_pressed = Input.is_key_pressed(event.scancode)
elif event is InputEventJoypadButton:
is_pressed = Input.is_joy_button_pressed(event.device, event.button_index)
elif event is InputEventMouseButton:
is_pressed = Input.is_mouse_button_pressed(event.button_index)
elif event is InputEventJoypadMotion:
is_pressed = Input.get_action_strength(action)
#add more elif to treat the type accordingly
else:
continue
if is_pressed:
break
return is_pressed
|
This allows an ActionNotifier to be pressed as long as one of the events that build up its action is still pressed, check godotengine/godot/pull/30890 for more
|
Cherry-picked for 3.1.2. |
That seems like a good solution. Would be nice to have at the engine level to reduce script complexity. |
I've extended this a bit to properly check the input axis values (since get_action_strength fails when another key is pressed and released) and add radial deadzones (so diagonal controls work better), in case this is useful to anyone: func is_pressed(action : String):
var is_pressed := false
for event in InputMap.get_action_list(action):
if event is InputEventKey:
is_pressed = Input.is_key_pressed(event.scancode)
elif event is InputEventJoypadButton:
is_pressed = Input.is_joy_button_pressed(event.device, event.button_index)
elif event is InputEventMouseButton:
is_pressed = Input.is_mouse_button_pressed(event.button_index)
elif event is InputEventJoypadMotion:
var axis : int = event.axis
var axis_sign := sign(event.axis_value)
var axis_val := Input.get_joy_axis(ControllerDevice, event.axis)# * axis_sign
var axis_positive := axis_val * axis_sign
var perpendicular_axis_val := 0.0
if (axis == JOY_ANALOG_LX):
perpendicular_axis_val = Input.get_joy_axis(ControllerDevice, JOY_ANALOG_LY)
elif (axis == JOY_ANALOG_LY):
perpendicular_axis_val = Input.get_joy_axis(ControllerDevice, JOY_ANALOG_LX)
elif (axis == JOY_ANALOG_RX):
perpendicular_axis_val = Input.get_joy_axis(ControllerDevice, JOY_ANALOG_RY)
elif (axis == JOY_ANALOG_RY):
perpendicular_axis_val = Input.get_joy_axis(ControllerDevice, JOY_ANALOG_RX)
var value_2d := Vector2(axis_val, perpendicular_axis_val)
var length := value_2d.length()
if (length > ControllerDeadzone):
var deadzone := (value_2d.normalized() * ControllerDeadzone).x # Circular deadzone
var wedge_deadzone := 0.4142135623730950488016887242097 * abs(perpendicular_axis_val) # 1 / tan(3/4 90 degrees). The slope of 1/8 of a circle
if (wedge_deadzone > deadzone):
deadzone = wedge_deadzone
if (axis_positive > deadzone):
is_pressed = true
else:
continue
if is_pressed:
break
return is_pressedNote: Can't be a static function anymore (unless the deadzone value and controller ID are passed in). |
|
Thank you for this workaround. I believe this should be the intended functionality in Godot, rather than what is currently there. Just consider the common use case of creating an action for "move_right", which devs will typically poll with Input.get_action_pressed("move_right"). On Godot's current way of doing things, if player accidentally touches d-pad right when primarily using analog stick right, or vice versa, the polling of the method is bound to return false, and suddenly player has no input until they release and repress. |
This should be addressed by #47599 if it's merged. |
For some reason this didn't work with my keyboard but I added the ...
if event is InputEventKey:
is_pressed = Input.is_key_pressed(event.scancode) or Input.is_key_pressed(event.physical_scancode)
... |
|
Hey, I'm trying to use this extended |
Supposed to resolve #30888