Disabling input stops physics process - help

Godot 4.5

Question

I’m a newb and I suck at coding, surprise surprise, so I’m not sure about how I should handle killing my player character. Whenever I go into my player script and try to disable input via Godot commands (set_process_input = false, for example) nothing happens. If I set a condition to stop input handling (eg: if is_dead = true, then pass) then it also stops tracking the player’s velocity; this would work okay if I had a death animation in place, but I’m not sure I really want that in the traditional sense. My end goal (eventually) is to have the player touch an enemy, die, and have them get launched in a random direction; the idea is that the momentum of the player before they touched the enemy will remain or something like that.

Anyway, that’s for later. For now, I just want it so whatever direction the player was moving in is retained BUT the player cannot input anymore. How do I make it so the physics process continues where the player left off (ex: they were holding left and died on an enemy) while also disabling player input?

Thanks.

Code:

extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

@onready var dude: Sprite2D = $Dude
@onready var hitbox1: CollisionShape2D = $hitbox1
@onready var hitbox2: CollisionShape2D = $hitbox2
var can_receive_input := true

#func die():
#Lifedata.health = 0
#Lifedata.is_alive = false

#func hit():
#Lifedata.health -= 1
#if Lifedata.health <=0:
#die()

func _physics_process(delta: float) → void:

if not is_on_floor():
	velocity += get_gravity() * delta

# Handle jump.
if Input.is_action_just_pressed("spacebar") and is_on_floor(): #and Lifedata.is_alive:
	velocity.y = JUMP_VELOCITY
else:
	pass
# Get the input direction (-1, 0, 1)
if Lifedata.is_alive:
	var direction := Input.get_axis("left", "right")
	
	if direction > 0 and hitbox1 and hitbox2:
		dude.flip_h = false
		hitbox1.position.x = -55.0
		hitbox2.position.x = -23.5
		
		
	if direction < 0 and hitbox1 and hitbox2:
		dude.flip_h = true
		hitbox1.position.x = -17.5
		hitbox2.position.x = -49
		
	# handle movement/deceleration
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
	
	move_and_slide()
else:
	pass

For context, the enemy code is set so when the player touches the enemy, the player hitboxes are queue_free’d and it plays a sound. A timer node starts when the player touches the enemy. After 2-3 seconds, the timer stops and the player is reset; all hitboxes are un queue_free’d, health is restored, and the scene is reloaded.

set_process_input(false) only disables the _input function, not Input entirely. Your Lifedata.is_alive is a great start, but you need to separate some parts of your physics process, move_and_slide for example should always process, chances are you also want to slow the character down when dead

if Lifedata.is_alive:
	# alive, handle movement/deceleration
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
else:
	# if dead slow down
	velocity.x = move_toward(velocity.x, 0, SPEED)
# always move_and_slide
move_and_slide()

Cool, I have moved move_and_slide() down so it is always processing. But that isn’t all I needed: how do I actually disable Input at this point?

I changed it so every time you die, the direction you are facing is where the player character will go. But you can still input which changes your direction midair. Here’s my code. If there’s anything I can do to improve it (and I’m sure there is) I ask you to please let me know.

func _physics_process(delta: float) → void:

if not is_on_floor():
	velocity += get_gravity() * delta

# Handle jump.
if Input.is_action_just_pressed("spacebar") and is_on_floor(): #and Lifedata.is_alive:
	velocity.y = JUMP_VELOCITY
else:
	pass
# Get the input direction (-1, 0, 1)
if Lifedata.is_alive:
	var direction := Input.get_axis("left", "right")
	
	if direction > 0 and hitbox1 and hitbox2:
		dude.flip_h = false
		hitbox1.position.x = -55.0
		hitbox2.position.x = -23.5
		
		
	if direction < 0 and hitbox1 and hitbox2:
		dude.flip_h = true
		hitbox1.position.x = -17.5
		hitbox2.position.x = -49
		
	# handle movement/deceleration
	if direction:
		velocity.x = direction * speed
	elif Lifedata.is_dead:
		if direction > 0:
			speed = 300.0
			velocity.x = speed
		if direction < 0:
			speed = -300.0
			velocity.x = speed
	else:
		velocity.x = move_toward(velocity.x, 0, speed)
	
else:
	velocity.x = move_toward(velocity.x, 0, speed)
move_and_slide()

Don’t process any input if the character is dead.

Great! How do I do that? That is what I would like to know on this day.

Right now, I just have one script that handles player input and physics (the one you can see above). Input and the physics process are tied, and I don’t want that to be the case, but I just don’t get how I would do it.

I was thinking maybe I could make a child node of the player scene that handles input, then just disable it whenever Lifedata.is_dead is true. That way the physics process in the main player script continues, and when the flag is triggered only the input node will stop being processed. I just don’t know how to handle it. Can you help me?

Using an if statement:

if not player_is_dead:
	# read input

Do you just mean the sprite’s facing direction, dude.flip_h? Not movement direction velocity?

It seems like your elif Lifedata.is_dead: never runs, unless you’ve stopped updating Lifedata.is_alive, in addition it’s an elif that only runs if no direction is pressed.

if is_alive:
   if direction: # runs if any direction is pressed
   elif is_dead: # only runs if dead, but we just confirmed is_alive.

Can you make sure the code you are pasting is between three back ticks? It’s difficult to discern your indentation.

I mean movement direction (velocity). In my code, if you are holding left and you die (direction > 0), var speed is set to -300.0, which changes velocity.x (velocity.x = speed). If you are holding right, speed is set to 300.0. The elif contains all of the code, and I have seen it work (so it must be running). I just want it so input stops being handled for the player when it touches an enemy and dies. I would also want the last direction value (-1, 0, or 1) to be maintained; if you are holding a button and touch an enemy, the direction value is -1 or whatever, but input stops being handled in that moment so you can’t change direction mid death. It seems like it should be simple, but I’m crap at coding because I’m new to godot. I’ll post my code with the method you mentioned so it is more clear.

Oh, and you’re right about Lifedata.is_alive. I have it unused right now because when I trigger it as false, it doesn’t retain the player’s direction (since it is literally holding the entire direction mechanic together) Sorry, I’m not that organized right now. That might actually be the key to solving this simply and quickly.

(side note, ignore the “jumpcounter” stuff I added. Just some double jump things im experimenting with)

func _physics_process(delta: float) -> void:
	
	if not is_on_floor():
		velocity += get_gravity() * delta

	# Handle jump.

	if is_on_floor():
		jumpcounter = 0
		
	if Input.is_action_just_pressed("spacebar"): #and is_on_floor(): #and Lifedata.is_alive:
		if jumpcounter < maxjumps:
			velocity.y = JUMP_VELOCITY
			jumpcounter +=1
	else:
		pass
	# Get the input direction (-1, 0, 1)
	if Lifedata.is_alive:
		var direction := Input.get_axis("left", "right")
		
		if direction > 0 and hitbox1 and hitbox2:
			dude.flip_h = false
			hitbox1.position.x = -55.0
			hitbox2.position.x = -23.5
			
			
		if direction < 0 and hitbox1 and hitbox2:
			dude.flip_h = true
			hitbox1.position.x = -17.5
			hitbox2.position.x = -49
			
		# handle movement/deceleration
		if direction:
			velocity.x = direction * speed
		elif Lifedata.is_dead:
			if direction > 0:
				speed = 300.0
				velocity.x = speed
			if direction < 0:
				speed = -300.0
				velocity.x = speed
		else:
			velocity.x = move_toward(velocity.x, 0, speed)
		
	else:
		velocity.x = move_toward(velocity.x, 0, speed)
	move_and_slide()

Well let your code stop handling it then. You know exactly which parts of your code are reading the input. Simply execute those parts only if player is alive by putting them into if blocks that test the player alive flag. That’s all there is to it.

I don’t think it’s working like you think then. This code always changes if direction is non-zero regardless of death, it just happens that speed is equal to 300, so velocity.x = direction * speed is the same as the elif Lifedata.is_dead.

Could be reduced to this

if direction:
	velocity.x = direction * speed
elif not Lifedata.is_dead: # not dead, then allow stopping
	velocity.x = move_toward(velocity.x, 0, speed)

I belive you should use the original snippet’s is_alive, and do not edit velocity when dead.

	if Lifedata.is_alive:
		var direction := Input.get_axis("left", "right")

		if direction > 0 and hitbox1 and hitbox2:
			dude.flip_h = false
			hitbox1.position.x = -55.0
			hitbox2.position.x = -23.5

		if direction < 0 and hitbox1 and hitbox2:
			dude.flip_h = true
			hitbox1.position.x = -17.5
			hitbox2.position.x = -49

		# handle movement/deceleration
		if direction:
			velocity.x = direction * speed
		else:
			velocity.x = move_toward(velocity.x, 0, speed)
	# always move and slide
	move_and_slide()

In your code, when the player dies you can set the velocity to exactly 300 in their last direction with this line

velocity.x = signf(velocity.x) * 300
1 Like

Gahhhhhh!!! I’m a moron. Thank you very much.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.