#How can I make a "universal" pause menu work?

40 messages · Page 1 of 1 (latest)

sage zephyr
#

I've been trying to use different methods for two days now, but nothing is working.

Here's code for reference:

extends Node

class_name GameManager

signal toggle_game_paused(is_paused : bool)

var game_paused : bool = false:
    get:
        return game_paused
    set(value):
        game_paused = value
        get_tree().paused = game_paused
        emit_signal("toggle_game_paused", game_paused)

func _input(event: InputEvent) -> void:
    if (event.is_action_pressed("pause")):
        print("Pause Button Pressed")
        game_paused = !game_paused

It works if I used a regular node as the root, but does that mean I have to do that for every level? Is there a way to make a universal pause menu work with one call?

true ridge
#

What about a global / autoload

sage zephyr
#

I wasn't sure how to handle that since I'm trying out a Global autoload that sorts out scenes.
This is my current Global Script:

extends Node

var coins := 0
const NUM_COINS_TO_WIN = 10
var game_controller : GameController


func _ready() -> void:
    pass

My GameController Script:

class_name GameController extends Node

@export var world_3d : Node3D
@export var world_2d : Node2D
@export var gui : Control

var current_3d_scene
var current_2d_scene
var current_gui_scene
# Called when the node enters the scene tree for the first time.

func _ready() -> void:
    Global.game_controller = self
    current_gui_scene = get_tree().change_scene_to_file("res://menu.tscn")
    
func change_gui_scene(new_scene: String, delete: bool = true, keep_running : bool = false) -> void:
    if current_gui_scene != null:
        if delete:
            current_gui_scene.queue_free() #removes node entirely
        elif keep_running:
            current_gui_scene.visible = false #keeps in memory and running
        else:
            gui.remove_child(current_gui_scene) #keeps in memory, does not keep running
    var new = load(new_scene).instantiate()
    gui.add_child(new)
    current_gui_scene = new

func change_3d_scene(new_scene: String, delete: bool = true, keep_running : bool = false) -> void:
    if current_3d_scene != null:
        if delete:
            current_3d_scene.queue_free() #removes node entirely
        elif keep_running:
            current_3d_scene.visible = false #keeps in memory and running
        else:
            world_3d.remove_child(current_3d_scene) #keeps in memory, does not keep running
    var new = load(new_scene).instantiate()
    world_3d.add_child(new)
    current_3d_scene = new

func change_2d_scene(new_scene: String, delete: bool = true, keep_running : bool = false) -> void:
    if current_2d_scene != null:
        if delete:
            current_2d_scene.queue_free() #removes node entirely
        elif keep_running:
            current_2d_scene.visible = false #keeps in memory and running
        else:
            world_2d.remove_child(current_2d_scene) #keeps in memory, does not keep running
    var new = load(new_scene).instantiate()
    world_2d.add_child(new)
    current_2d_scene = new


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
    pass

and my GameManager script I used to pause a scene:

extends Node

class_name GameManager

signal toggle_game_paused(is_paused : bool)

var game_paused : bool = false:
    get:
        return game_paused
    set(value):
        game_paused = value
        get_tree().paused = game_paused
        emit_signal("toggle_game_paused", game_paused)

func _input(event: InputEvent) -> void:
    if (event.is_action_pressed("pause")):
        print("Pause Button Pressed")
        game_paused = !game_paused
sage zephyr
#

As a global variable in the global autoload?

true ridge
#

Sure

sage zephyr
#

😅 It didn't do anything lol

#

I have it set to print "Pause Button Pressed" and nothing happened

true ridge
#

The pause menu node itself doesn't pause right?

sage zephyr
#

right I currently have its Process Mode set to When Paused

#

Game Manager is set to Always

#

Game Controller is also set to Always

#

I set my Level1 to Pausable as well as the World3D and World2D nodes in the Game Controller

#

GUI is set to Always

true ridge
#

If it's "when paused" then it can't trigger any functions to pause the game

#

Since it's paused when the tree is paused

sage zephyr
#

Oh! Ok so it should be set to always?

true ridge
#

Sure

sage zephyr
#

Is there a better setting for it?

true ridge
#

I don't think so

sage zephyr
#

I think I'm missing something that connects it to the level? I'm not sure if I can call a function for the pause in the level or game script

true ridge
#

If it's an autoload you can call it from anywhere

sage zephyr
#

changed the game manager to this:

extends Node

class_name GameManager

func _ready() -> void:
    Global.game_manager = self

signal toggle_game_paused(is_paused : bool)

var game_paused : bool = false:
    get:
        return game_paused
    set(value):
        game_paused = value
        get_tree().paused = game_paused
        emit_signal("toggle_game_paused", game_paused)

func _input(event: InputEvent) -> void:
    if (event.is_action_pressed("pause")):
        print("Pause Button Pressed")
        game_paused = !game_paused
#

and the pause menu script I forgot to add:

extends Control

@export var game_manager : GameManager

func _ready() -> void:
    hide()
    game_manager.connect("toggle_game_paused", _on_game_manager_toggle_game_paused)

func _on_game_manager_toggle_game_paused(is_paused : bool):
    if (is_paused):
        show()
    else:
        hide()


func _on_resume_button_pressed() -> void:
    game_manager.game_paused = false


func _on_options_button_pressed() -> void:
    pass # Replace with function body.


func _on_quit_button_pressed() -> void:
    pass # Replace with function body.
sage zephyr
#

Still at work but I can’t stop thinking about how to make this work.
Do I need to make the pause menu a resource or something like that?
Is there a way to attach the pause menu through code, or to use the Game Controller to attach the pause menu to whichever level is currently loaded?

true ridge
#

is the pause menu an autoload

sage zephyr
#

Oh you know what, I think I just have the global script as an autoload

#

If I make the pause menu an autoload should I change the root node to a Canvas Layer?

#

I kept thinking that having the Class variable in the Global script connected it to the autoload 😅 I’ll try adding it as another autoload item. Is there a way to make it only load for 3D and 2D nodes?

true ridge
#

i don't know what you mean

#

autoloads are loaded all the time

#

you can't choose when to load them

#

do you mean that it only pauses 3d and 2d nodes?

sage zephyr
#

Yeah that’s what I meant

#

That’s just making those nodes Pausable right? Or am I still missing something?

true ridge
#

yeah

sage zephyr
# true ridge yeah

ok none of that was working lol so now I'm trying to make the pause menu a child of the main character instead.
Took me a while to get it to work, but its good enough for what it is 😁 thank you for your help!

true ridge
#

okay 👍

lilac oak
#

If you're still on this issue;
I'd recommend you set up your pause menu as its own scene, with aCanvasLayer root node.
Then add the scene itself to your globals

#

when you add a scene to the globals, it instantiates it in any currently running scene.