Skip to content

UI State Manager

In v1.x, opening and closing inventories required manually toggling visible, calling InputMode.ui(), and managing mouse states.

In v2.0.0, the UIStateManager Autoload handles all of this automatically. It manages a stack of UI panels, handles background overlays, controls game pausing, and provides context for Quick-Moving items between open inventories.

Key Features

  • Stack Management: Open multiple panels (e.g., Player Inventory + Chest) and close them in order.
  • Automatic Mouse Handling: Automatically calls InputMode.ui() when a panel opens and InputMode.game() when all panels close.
  • Background Overlay: Automatically draws a semi-transparent dark background behind your UI panels.
  • Quick Context: Automatically tracks which inventories are open so SlotUI can perform Quick-Moves (Shift+Click) between them.
  • Global Shortcuts: Automatically closes all UIs when the player presses Escape (ui_cancel) or Right-Clicks (if not dragging).

Opening Panels

To open a UI, you pass a PackedScene (your saved .tscn UI), the Inventory resource to bind, a title, a layout role, and an optional pause type.

# Signature
UIStateManager.open_panel(
    scene: PackedScene, 
    inv: Inventory, 
    title: String = "", 
    role: String = "default", 
    type: UIStateManager.UIType = UIStateManager.UIType.BLOCK_INPUT
) -> Control

Layout Roles

The role parameter tells the UICoordinator where to place the panel on the screen: - "player": Anchors to the right side of the screen. - "container": Anchors to the left side (if a player UI is open) or centers itself. - "default": Places the UI dead center.

UI Types (Pausing)

  • UIType.BLOCK_INPUT: (Default) Freezes player movement/mouse capture, but the game world keeps running.
  • UIType.PAUSE_GAME: Actually pauses the Godot SceneTree (get_tree().paused = true). Useful for pause menus.

Closing Panels

You have several ways to close UIs depending on your needs:

# Closes every open panel, removes the background, and restores mouse capture.
UIStateManager.close_all()

# Closes only the most recently opened panel (top of the stack).
UIStateManager.close_top_ui()

# Closes a specific panel instance.
UIStateManager.close_panel(my_specific_panel_control)

Utility Methods

Checking UI State

# Returns true if ANY panels are currently open.
if UIStateManager.has_open_ui():
    print("Menus are open!")

Quick Move Context

When a player Shift+Clicks an item, the SlotUI needs to know where to send it. UIStateManager handles this automatically:

# Returns the Inventory of the *other* open panel (e.g., the chest, if the player inv is current).
var target_inv = UIStateManager.get_other_inventory(current_inventory)


Example: Opening a Chest

Here is a complete example of how to open a chest and the player's inventory side-by-side using the new manager.

extends Node3D

@export var player_ui_scene: PackedScene
@export var chest_ui_scene: PackedScene
@export var player_inv: InventoryComponent
@export var chest_inv: InventoryComponent

func _unhandled_input(event: InputEvent) -> void:
    if event.is_action_pressed("interact"): # e.g., Press 'E'
        if UIStateManager.has_open_ui():
            UIStateManager.close_all()
        else:
            open_chest()

func open_chest():
    # 1. Open Player Inventory (Role: "player" -> anchors right)
    UIStateManager.open_panel(
        player_ui_scene, 
        player_inv.inventory, 
        "Inventory", 
        "player"
    )

    # 2. Open Chest Inventory (Role: "container" -> anchors left)
    UIStateManager.open_panel(
        chest_ui_scene, 
        chest_inv.inventory, 
        "Chest", 
        "container"
    )

    # Note: You DO NOT need to call InputMode.ui() or UICoordinator manually!
    # UIStateManager handles the mouse cursor, background dimming, and layout automatically.

Signals

If you need to react to UIs opening or closing (e.g., to play a sound effect or trigger an animation), UIStateManager emits two global signals:

Signal Description
panel_spawned(panel: Control, scene: PackedScene, role: String) Emitted immediately after a panel is instantiated and added to the tree.
panel_closed(panel: Control) Emitted right before a panel is freed from the tree.