Godot Version
v4.7.2.stable.official [ed1daf0bf]
Running on macOS 26.6.2
Context and Goal
I’m prototyping a turn based, player-vs-bots game (not multiplayer).
When a player taps a key, their avatar and all the enemies execute for their turn. The animations for these turn last for a quarter of a second, at which point the player can tap a key again for the next turn to happen. Also, if the player is holding the same key down when the animation finishes, then that action should re-fire.
Code
In _unhandled_input, I check for the action (&Move) and move the position of my avatar via a tween. At the end of the tween I call end_tween with the action that was just animated.
The boolean is_tweening is used to stop this code processing a new action while and existing action is being animated. If I didn’t do this, the avatar would move off the grid spots.
Regardless of whether is_tweening is true or not, I set_input_as_handled for valid actions.
Print calls are for debugging/tracing purposes.
func _unhandled_input(event: InputEvent) -> void:
print( "UNHANDLED INPUT ", event.to_string() )
if event is InputEventAction:
var e = event as InputEventAction
print( " ACTION EVENT WITH STRENGTH ", e.strength )
if event.is_action_pressed( &"Move" ):
if not is_tweening:
is_tweening = true
var t : Tween = create_tween()
t.tween_property( avatar, "position", 2.0, 0.250 )
t.tween_callback( end_tween.bind( &"Move" ) )
current_viewport.set_input_as_handled()
The code for end_tween turns is_tweening off and then checks to see if the provided action_name is still being pressed. If so, it creates a new InputEvent and issues it using Input.parse_input_event.
The strength_counter variable starts with a value of 1.0 and is decremented each time I create a new InputEvent. This is purely for debugging purposes so I could check whether I was getting new events or somehow reprocessing the first event over and over.
Print calls are for debugging/tracing purposes.
func end_tween( action_name: StringName ) -> void:
is_tweening = false
print( "TWEEN ENDED FOR ACTION ", action_name )
if Input.is_action_pressed( action_name ):
var event : InputEvent = InputEventAction.new()
event.action = action_name
event.pressed = true
event.strength = str_counter
str_counter -= 0.01
Input.parse_input_event( event )
print( "BUTTON STILL DOWN FOR ACTION ", action_name, ". CREATED NEW ACTION WITH STRENGTH", str_counter )
else:
print( "BUTTON NO LONGER DOWN FOR ACTION ", action_name )
Bug
When I tap the key once. Everything works fine.
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move
When I tap the key twice, fast enough. Everything works fine.
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move
When I tap the key twice, slow enough. Everything works fine.
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move
When I press and hold, and trigger the creation of an InputEvent things go wrong.
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.99
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 1.0
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=true
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.98
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 0.99000000953674
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.97
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 0.98000001907349
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.96
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 0.97000002861023
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.95
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 0.95999997854233
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.94
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 0.94999998807907
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.93
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
ACTION EVENT WITH STRENGTH 0.93999999761581
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.92
As you can see, I get a pressed event, an echo event, and a released event, but the code in end_tween continues to see the action as pressed, causing a loop.
Note also, that the strength changes as expected, meaning we really are creating new events.
Also, when I watch it run, I can see that the logs are printed out at quarter second intervals.
Question
What am I misunderstanding about this functionality?
I do have another way of re-writing this code so that I don’t have to use Input.parse_input_event which I’ll try. But I’d still like to know what I’ve done wrong here.