How can I tie pause and unpause to the same key without both happening in a single frame?

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

func _ready():
	$Panel.hide()
	pause_mode = Node.PAUSE_MODE_PROCESS

func on_interact(player):	
	if not $Panel.visible:
		$Panel.show()
		get_tree().paused = true

func _input(event):
	if Input.is_action_just_pressed("interact") and $Panel.visible:
		$Panel.hide()
		get_tree().paused = false

This is the script for an object the player can interact with, which shows a panel with a TextureRect. (They’re examining a poster on the wall.) I want the game to pause while the interaction is happening, and then unpause when the player presses Interact again. But right now, it’s all happening in a single frame, so in-game it looks like nothing happens at all.

I think the best option might be a timer that triggers a boolean, but I figured I’d see if anyone had a better idea.

:bust_in_silhouette: Reply From: exuin

You can disable and enable the _input function with set_process_input. Or you can put it in the _unhandled_input function instead of using the _input function (just make to sure to consume the interaction input beforehand).

Hm, I haven’t been exposed to _unhandled_input till now. It looks handy and your solution makes sense in theory, but I’m having a hard time getting it to work. What do you mean by “consuming” the interaction input beforehand?

shevek | 2021-05-30 00:14

:bust_in_silhouette: Reply From: wyattb

Why cant you do it this way:

func _input(event):
    if Input.is_action_just_pressed("interact"):
        if $Panel.visible:
            $Panel.hide()
            get_tree().paused = false
        else:
            $Panel.show()
            get_tree().paused = true

Well, the initial Interact action comes from Player.gd, and it’s also based on a collision with the Player’s Raycast2D, to ensure that the player is facing the object they’re interacting with.

Though I suppose I could have the Raycast2D simply activate the interactable object it’s colliding with, and then put your Input code on the object itself.

I ended up going with the timer + boolean idea. It seemed jankier at first, but upon implementation, I actually like the more weighty feel it gives the interaction.

shevek | 2021-05-30 00:00