Using unhandled_input for movement

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By jujumumu

The current code I use for movement is this. Note that this is in the _physics_process() function.

if Input.is_key_pressed(KEY_A):
	motion.x = -SPEED
	direction='left'
elif Input.is_key_pressed(KEY_D):
	motion.x = SPEED
	direction='right'
else:
		motion.x=0

The problem with this is that if I try to type something in the game like chat and I press the “a” or “d” key it would still move the player. To stop this I used this code in the _unhandled_input() function.

elif event is InputEventKey:
	if event.scancode==KEY_A:
		if event.is_pressed():
			motion.x=-SPEED
		else:
			motion.x=0
	elif event.scancode==KEY_D:
		if event.is_pressed():
			motion.x=SPEED
		else:
			motion.x=0

This code isn’t as responsive like whenever I want to suddenly change direction it stops for a bit then moves in the opposite direction. What should I do?

:bust_in_silhouette: Reply From: kidscancode

_unhandled_input() is the right place for this. If you’re using Control nodes for chat input, then they will capture input first and you can stop them propagating.

There is a specific sequence that an InputEvent follows when propagating through the engine.

See here: Using InputEvent — Godot Engine (3.2) documentation in English

The problem is that the new code I’m using doesn’t work as expected. It’s not as smooth as the old code. Am I doing something wrong? No matter how hard I search google the movement code in demos are always in _physics_process().

jujumumu | 2020-04-19 01:07

I’m not really sure what that means. You’ve only included snippets of your code, so I can’t speculate what may be going on with “smoothness”.

Of course movement code should be in _physics_process(). That doesn’t mean input code has to be. That said, there’s nothing wrong with polling using Input. Again, speaking to your original problem, if you have UI capturing input, it can be consumed and not passed along to other nodes.

kidscancode | 2020-04-19 01:16

This was my old movement code

func _physics_process(delta):
	motion.y += GRAVITY*delta
	if Input.is_key_pressed(KEY_A):
		motion.x = -SPEED
	elif Input.is_key_pressed(KEY_D):
		motion.x = SPEED
	else:
		motion.x=0
	
	if is_on_floor():
		if Input.is_key_pressed(KEY_SPACE):
			motion.y = JUMP_HEIGHT

	motion = move_and_slide(motion, UP)

This is my new movement code

func _unhandled_input(event):
    if event is InputEventKey:
		if event.scancode==KEY_A:
			if event.is_pressed():
				motion.x=-SPEED
			else:
				motion.x=0
		elif event.scancode==KEY_D:
			if event.is_pressed():
				motion.x=SPEED
			else:
				motion.x=0

func _physics_process(delta):
	motion.y += GRAVITY*delta
	
	if is_on_floor():
		if Input.is_key_pressed(KEY_SPACE):
			motion.y = JUMP_HEIGHT

	motion = move_and_slide(motion, UP)

Is this how the codes supposed to go?

jujumumu | 2020-04-19 02:08

No, because that only resets the motion.x to 0 when an event occurs. If you want continuous movement, you want to poll the key state, like in your first example.

Once again, nothing to do with your initial question, which wasn’t about movement at all, but about capturing input in a completely different UI node.

Also, is_on_floor() should only be called after move_and_slide(), as that’s how the on_floor state gets set.

kidscancode | 2020-04-19 06:49

How do I poll the key state for the new code?

jujumumu | 2020-04-20 01:43

I’m having the same problem, I can’t make unhandled input work, my character stops when I keep a movement key pressed. What I want is to be able to open a debug console without pausing the game, I was using Input polling just like your first example and the movement was smooth but the debug console wouldn’t work, there was no output. I then moved the movement input to unhandled input and now the debug console works fine but the movement is broken. Here’s my character movement before:

func _physics_process(delta):
	if Input.is_action_just_pressed("hack"):
		hacking = !hacking
	if hacking:
		movement_speed = 0
		get_parent().add_child(load("res://scenes/Terminal.tscn").instance())
		get_parent().add_child(load("res://scenes/Hud.tscn").instance())
				
		if raycast.is_colliding():
			if raycast.get_collider().is_in_group("Enemy"):
				raycast.get_collider().focus_toggle()
	else:
		var h_rot = $Camroot/h.global_transform.basis.get_euler().y
		if Input.is_action_pressed("forward") ||  Input.is_action_pressed("backward") ||  Input.is_action_pressed("left") ||  Input.is_action_pressed("right"):
			if Input.is_action_pressed("crouch"):
				direction = Vector3(Input.get_action_strength("left") - Input.get_action_strength("right"),
								0,
								Input.get_action_strength("forward") - Input.get_action_strength("backward"))
				strafe_dir = direction
				direction = direction.rotated(Vector3.UP, h_rot).normalized()
				movement_speed = 3*walk_speed/2
			elif Input.is_action_pressed("run"):
				direction = Vector3(Input.get_action_strength("left") - Input.get_action_strength("right"),
								0,
								Input.get_action_strength("forward") - Input.get_action_strength("backward"))
				strafe_dir = direction
				direction = direction.rotated(Vector3.UP, h_rot).normalized()
				movement_speed = run_speed
			else:
				direction = Vector3(Input.get_action_strength("left") - Input.get_action_strength("right"),
								0,
								Input.get_action_strength("forward") - Input.get_action_strength("backward"))
				strafe_dir = direction
				direction = direction.rotated(Vector3.UP, h_rot).normalized()
				movement_speed = walk_speed
		else:
			movement_speed = 0
			direction = $Camroot/h.global_transform.basis.z
			if Input.is_action_pressed("crouch"):
				anim_tree.set("parameters/Crouched/blend_amount",1)
				anim_tree.set("parameters/IW/blend_amount",0)
			else:
				anim_tree.set("parameters/Crouched/blend_amount",0)
				anim_tree.set("parameters/IWR/blend_amount",-1)			
		if Input.is_action_just_pressed("roll"):
			direction = Vector3(Input.get_action_strength("left") - Input.get_action_strength("right"),
							0,
							Input.get_action_strength("forward") - Input.get_action_strength("backward"))
			strafe_dir = direction
			direction = direction.rotated(Vector3.UP, h_rot).normalized()
			movement_speed = walk_speed
			anim_tree.set("parameters/Roll/active",true)
		velocity = lerp(velocity, direction * movement_speed, delta * acceleration)
		if sqrt(velocity.x*velocity.x + velocity.y*velocity.y) > 0.5:
			move_and_slide(velocity + Vector3.DOWN * vertical_velocity, Vector3.UP)
			$Mesh.rotation.y = lerp_angle($Mesh.rotation.y, $Camroot/h.rotation.y, delta * angular_acceleration)
			strafe = lerp(strafe, strafe_dir + Vector3.RIGHT * aim_turn, delta * acceleration)
	if !is_on_floor():
		vertical_velocity += gravity * delta
	else:
		vertical_velocity = 0

And now the new code. I keep pressing any movement key, the character only moves once and then stops. I know there must be some easy way of solving this, I’m still learning Godot, but I can’t find something similar on the web (other than this post ;)). The new code is (deleted some animation tree calls for brevity):

func _unhandled_input(event):
	if event is InputEventKey:
		if !hacking:
			if event.is_action_pressed("hack"):
				hacking = !hacking
				movement_speed = 0
				get_parent().add_child(load("res://scenes/Terminal.tscn").instance())
				get_parent().add_child(load("res://scenes/Hud.tscn").instance())
						
				if raycast.is_colliding():
					if raycast.get_collider().is_in_group("Enemy"):
						raycast.get_collider().focus_toggle()
			else:
				var h_rot = $Camroot/h.global_transform.basis.get_euler().y
				if event.is_action_pressed("forward") ||  event.is_action_pressed("backward") ||  event.is_action_pressed("left") ||  event.is_action_pressed("right"):
					if event.is_action_pressed("crouch"):
						direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
										0,
										event.get_action_strength("forward") - event.get_action_strength("backward"))
						strafe_dir = direction
						direction = direction.rotated(Vector3.UP, h_rot).normalized()
						movement_speed = 3*walk_speed/2
					elif event.is_action_pressed("run"):
						direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
										0,
										event.get_action_strength("forward") - event.get_action_strength("backward"))
						strafe_dir = direction
						direction = direction.rotated(Vector3.UP, h_rot).normalized()
						movement_speed = run_speed
					else:
						direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
										0,
										event.get_action_strength("forward") - event.get_action_strength("backward"))
						strafe_dir = direction
						direction = direction.rotated(Vector3.UP, h_rot).normalized()
						movement_speed = walk_speed
				else:
					movement_speed = 0
					direction = $Camroot/h.global_transform.basis.z
					if event.is_action_pressed("crouch"):
						anim_tree.set("parameters/Crouched/blend_amount",1)
						anim_tree.set("parameters/IW/blend_amount",0)
					else:
						anim_tree.set("parameters/Crouched/blend_amount",0)
						anim_tree.set("parameters/IWR/blend_amount",-1)			
				if event.is_action_pressed("roll"):
					direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
									0,
									event.get_action_strength("forward") - event.get_action_strength("backward"))
					strafe_dir = direction
					direction = direction.rotated(Vector3.UP, h_rot).normalized()
					movement_speed = walk_speed
					anim_tree.set("parameters/Roll/active",true)
func _physics_process(delta):
	velocity = lerp(velocity, direction * movement_speed, delta * acceleration)
	if sqrt(velocity.x*velocity.x + velocity.y*velocity.y) > 0.5:
		move_and_slide(velocity + Vector3.DOWN * vertical_velocity, Vector3.UP)
		$Mesh.rotation.y = lerp_angle($Mesh.rotation.y, $Camroot/h.rotation.y, delta * angular_acceleration)
		strafe = lerp(strafe, strafe_dir + Vector3.RIGHT * aim_turn, delta * acceleration)	
	if !is_on_floor():
		vertical_velocity += gravity * delta
	else:
		vertical_velocity = 0

If anyone knows of a way to solve this, I would appreciate it very much. It seems my question is the same as yours: How do I poll the key state for the new code?

alvarocafe | 2020-08-07 20:16

Figured out how to make the character keep moving when polling from unhandled input. We need to set the allow echo variable to true in the is_pressed function. New code the character moves ok, but doesn’t stay crouched neither runs. I think writing the previous message helped me think about my problem, but I also ran into this question which gave the answer I wanted. To set the variable allow echo to true, just pass to as a second argument in the event.is_action_pressed function, so

event.is_action_pressed("forward") 

should be

event.is_action_pressed("forward",true) 

The question with the information about this is on this link:
https://forum.godotengine.org/3151/when-key-is-released-rather-than-when-key-is-pressed

My new code:

func _unhandled_input(event):
	if event is InputEventKey:
		print(hacking)
		if !hacking:
			if event.is_action_pressed("hack"):
				hacking = !hacking
				movement_speed = 0
				anim_tree.set("parameters/Crouched/blend_amount",1)
				anim_tree.set("parameters/IW/blend_amount",0)
				get_parent().add_child(load("res://scenes/Terminal.tscn").instance())
						
				if raycast.is_colliding():
					if raycast.get_collider().is_in_group("Enemy"):
						raycast.get_collider().focus_toggle()
			else:
				anim_tree.set("parameters/Crouched/blend_amount",0)
				anim_tree.set("parameters/IW/blend_amount",-1)
				var h_rot = $Camroot/h.global_transform.basis.get_euler().y
				if event.is_action_pressed("forward",true) ||  event.is_action_pressed("backward",true) ||  event.is_action_pressed("left",true) ||  event.is_action_pressed("right",true):
					if event.is_action_pressed("crouch",true):
						direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
										0,
										event.get_action_strength("forward") - event.get_action_strength("backward"))
						strafe_dir = direction
						direction = direction.rotated(Vector3.UP, h_rot).normalized()
						movement_speed = 3*walk_speed/2
						anim_tree.set("parameters/IWR/blend_amount",0)
		
						anim_tree.set("parameters/IW/blend_amount",1)
					elif event.is_action_pressed("run",true):
						direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
										0,
										event.get_action_strength("forward") - event.get_action_strength("backward"))
						strafe_dir = direction
						direction = direction.rotated(Vector3.UP, h_rot).normalized()
						movement_speed = run_speed
						anim_tree.set("parameters/IWR/blend_amount",0)
						anim_tree.set("parameters/IWR/blend_amount",1)
					else:
						direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
										0,
										event.get_action_strength("forward") - event.get_action_strength("backward"))
						strafe_dir = direction
						direction = direction.rotated(Vector3.UP, h_rot).normalized()
						movement_speed = walk_speed
						anim_tree.set("parameters/IWR/blend_amount",0)
				else:
					movement_speed = 0
					direction = $Camroot/h.global_transform.basis.z
					if event.is_action_pressed("crouch"):
						anim_tree.set("parameters/Crouched/blend_amount",1)
						anim_tree.set("parameters/IW/blend_amount",0)
					else:
						anim_tree.set("parameters/Crouched/blend_amount",0)
						anim_tree.set("parameters/IWR/blend_amount",-1)			
				if event.is_action_pressed("roll"):
					direction = Vector3(event.get_action_strength("left") - event.get_action_strength("right"),
									0,
									event.get_action_strength("forward") - event.get_action_strength("backward"))
					strafe_dir = direction
					direction = direction.rotated(Vector3.UP, h_rot).normalized()
					movement_speed = walk_speed
					anim_tree.set("parameters/Roll/active",true)
			
func _physics_process(delta):
	velocity = lerp(velocity, direction * movement_speed, delta * acceleration)
	if sqrt(velocity.x*velocity.x + velocity.y*velocity.y) > 0.5:
		move_and_slide(velocity + Vector3.DOWN * vertical_velocity, Vector3.UP)

		$Mesh.rotation.y = lerp_angle($Mesh.rotation.y, $Camroot/h.rotation.y, delta * angular_acceleration)
		strafe = lerp(strafe, strafe_dir + Vector3.RIGHT * aim_turn, delta * acceleration)	
	if !is_on_floor():
		vertical_velocity += gravity * delta
	else:
		vertical_velocity = 0

alvarocafe | 2020-08-08 14:46