Linking two Canvas Layer scenes with signals

Godot Version

4.7.1

Question

Hi! I’m having trouble creating a pause menu that opens submenus using canvas layers. I’ve been following jorge robles JRPG tutorial and got up to the inventory system which uses a canvas layer to create the UI.

I wanted to change how the inventory was opened to a system closer to what you might find in an rpgmaker project. So open pause menu → pressbutton → Open adjacent interactable screen. Press esc to back out to pause, then esc again to return to game.

I though I would be able to simply connect up the pause menu buttons to the open() function in the inventory screen with Signals. I made sure my PauseMenu scene is an Autoload so I can eventually send signals to other screen scenes. But It doesn’t show at all. I’m not sure where I’m going wrong.

PauseMenu Script:

extends CanvasLayer

@onready var _panel: PanelContainer = $PanelContainer

signal call_inv 

func _ready() -> void:
	_panel.visible = false

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel") and get_tree().paused:
		_resume()
		get_viewport().set_input_as_handled()
	elif event.is_action_pressed("pause") and !get_tree().paused:
		_pause()
		get_viewport().set_input_as_handled()


func _resume() -> void:
	get_tree().paused = false
	_panel.visible = false


func _pause() -> void:
	get_tree().paused = true
	_panel.visible = true
	$PanelContainer/VBoxContainer/Resume.grab_focus.call_deferred()

func _on_resume_pressed() -> void:
	_resume()

func _on_inventory_pressed() -> void:
	call_inv.emit()

InventoryScreen Script:

extends CanvasLayer
## The inventory screen. Opens/closes with the menu key.

const itemSlotScene := preload("res://ui/inventory/item_slot.tscn")

#region @onready
@onready var _panel: PanelContainer = $PanelContainer
@onready var _item_grid: GridContainer = $PanelContainer/MarginContainer/VBoxContainer/ItemGrid
@onready var _gold_label: Label = $PanelContainer/MarginContainer/VBoxContainer/Header/GoldLabel
@onready var _description_label: RichTextLabel = $PanelContainer/MarginContainer/VBoxContainer/DescriptionLabel
#endregion

var _is_open: bool = false

func _ready() -> void:
	_panel.visible = false
	
    #PauseMenu Signal
	PauseMenu.call_inv.connect(open)
	
	InventoryManager.inventory_changed.connect(_refresh)
	InventoryManager.gold_changed.connect(_on_gold_changed)
	_update_gold_display()

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel") or event.is_action_pressed("menu") and _is_open: # Close Inventory
		close()
		get_viewport().set_input_as_handled()
	elif event.is_action_pressed("menu") and not _is_open:
		# Old open code
        open()
		get_viewport().set_input_as_handled()

func open() -> void:
	_show()

func _show() -> void:
	_is_open = true
	_panel.visible = true
	#get_tree().paused = true (Removed as pausing is handled in PauseMenu)
	_refresh()

PauseMenu:

  • Process Mode: Always
  • CanvasLayer Layer: 1

InventoryScreen:

  • Process Mode: When Paused (Idea being that it can only be accessed when Pause menu is open)
  • CanvasLayer Layer: 2

I feel like I must have misunderstood how Signals or CanvasLayers work. Or both of them. Any advice would be appreciated, thank you!

Throw some print statements in _on_inventory_pressed and other strategic places to understand what’s going on and what might not be working as expected.

Admittedly I was frustrated last night and completely forgot to do a bunch of print statements ^^;

I went about checking the signals and it all seemed to be connecting, it just would not call the open function despite being connect. I thought to make sure the nodes where definitely in the scene tree at the same time. Only to realise that Pause Menu was entering the scene tree twice. Because I’d made it an autoload I didn’t need it in the scene tree as I believe it should already be loaded at root? Removing the Pause Menu scene from the map scene seems to have fixed the issue!