Issue with using _unhandled_key_input()

Godot Version

4.3

Question

I am trying to figure out the best way to handle moving the character in my game, and the docs suggest me to use _unhandled_key_input() for gameplay input. However, using something like

func _unhandled_key_input(event: InputEvent) -> void:
	velocity = Vector2(0, 0)
	if event.is_action_pressed("move_left", true):
		velocity.x -= speed
	if event.is_action_pressed("move_right", true):
		velocity.x += speed
	if event.is_action_pressed("move_up", true):
		velocity.y -= speed
	if event.is_action_pressed("move_down", true):
		velocity.y += speed
	return

only lets the character move in a cardinal direction at a time(no movements at 45 degrees or such). I believe this is because when the second key is pressed after one direction key is pressed, _unhandled_key_input gets called again and velocity is reset to 0. Is there a way to use this function for moving in directions like north west or do I use the Input singleton in _physics_process(like in squash the creeps demo)?

You could try something along the following idea:

var velocity = Vector2(0, 0)
func _unhandled_key_input(event: InputEvent) -> void:
	if event.is_action_pressed("move_left", true):
		velocity.x -= speed
	elif event.is_action_pressed("move_right", true):
		velocity.x += speed
	elif event.is_action_pressed("move_up", true):
		velocity.y -= speed
	elif event.is_action_pressed("move_down", true):
		velocity.y += speed
	elif event.is_action_released("move_left", true):
		velocity.x += speed
	elif event.is_action_released("move_right", true):
		velocity.x -= speed
	elif event.is_action_released("move_up", true):
		velocity.y += speed
	elif event.is_action_released("move_down", true):
		velocity.y -= speed
	return

and act on velocity in _physics_process`.

Check out Input.get_vector()

1 Like

Thanks, but that would require using the Input singleton inside _unhandled_key_input(), which would both make event which is passed as a parameter to _unhandled_key_input() pointless and can be buggy. If I was going to use the Input singleton I’d have used is_action_pressed() of Input in _unhandled_key_input(). I want a solution using InputEvent

I could just write a massive if chain to detect all 8 directions if that’s what you mean, but I think that’s a last resort, and possibly worse than just using the Input singleton

You can also just check if the event is a movement action before the get vector. it isnt buggy at all and you get a normalized vector. And you are already using the Input singleton via the _unhandled_input callback.

Whoa, the _unhandled_input callbacks use the Input singleton? Didn’t know that

As for the buggy part, I was encountering a weird bug with interactions with walls at the start of my project, but not now, so I suppose that was not Input related

Do inputs that are detected through the Input singleton’s functions also have the mechanism of getting accepted?

oh wait sorry I just re read your post and that makes total sense. However it’s just a bit buggy when I encounter walls in my project, move_and_slide then makes it zero and when I release the key it increases the velocity in the opposite direction. This also makes it tough to go forward when a wall is encountered.

Im not sure i understand exactly what you mean.

Every frame, As physical inputs happen, they are temporarily buffered by the input Singleton. The displayserver flushes the Singleton buffer. During the flush, global input state is updated, and inputevents/actions are created and dispatched one by one to the scenetree/viewport. There is a big order of operations you can see here.

That link also explains a lot about how to stop propagation. But general rule of thumb custom UI can use _input and game characters can use unhandled*input events.

Tbh im not sure why there is a special unhandled key input when the general purpose one can handle it all, seems kind of elitist :wink:

Aight, thx!