UI Components at a Glance

The level UI is split into three layers: HUD overlays that track live stats, modal windows opened on demand, and notification toasts triggered from code.

LayerComponentPurpose
HUDPlayerHealthBarRow of heart toggles that mirrors the player's current HP.
HUDPlayerStaminaBarRow of pip toggles that mirrors the player's current stamina.
HUDHUD_ShowStatEffectNumberFloating numbers that pop above a character whenever damage, healing, or a block occurs.
Enemy HUDEnemyHealthBarNumeric HP label on each enemy, updated on every hit.
Enemy HUDEnemyActionSequencePanelGrid of action icons showing the full enemy sequence on hover.
Enemy HUDEnemyInstructionIndicatorAnimated icon that transitions to match the enemy's active action.
WindowsInventoryWindowFull-screen inventory displaying equipment slots, item slots, and stat totals.
WindowsWinScreenControllerModal overlay shown automatically when the level is completed.
WindowsGameOptionsMenuIn-game options panel with volume controls and map return.
NotificationsNotificationLayoutToast pop-up with icon and message that auto-dismisses after 7 seconds.
NotificationsEquipmentNotificationQueued pop-up that announces newly received equipment items.

Step 1 — Player HUD Bars

PlayerHealthBar and PlayerStaminaBar subscribe to LevelManager events automatically at startup ([DefaultExecutionOrder(10)]). No manual wiring to LevelManager is needed — place either component anywhere in the Canvas and assign its two Inspector fields.

ComponentFieldTypeWhat to assign
PlayerHealthBarheartPrefabToggleToggle prefab spawned once per maximum HP point.
healthContainerTransformParent transform that receives the spawned heart toggles.
PlayerStaminaBarpointPrefabToggleToggle prefab spawned once per maximum stamina point.
containerTransformParent transform that receives the spawned stamina pip toggles.

Both bars destroy and re-spawn their toggles on each LevelManager.OnInitialize event, so the counts always match the LevelInfo values at the start of a run.

Step 2 — Floating Stat Numbers

Add HUD_ShowStatEffectNumber as a child of any GameObject that owns a Health or PlayerStamina component. The script finds those components via GetComponentInParent in Start() and subscribes automatically — no Inspector wiring is required.

Customise the three color fields in the Inspector to control how each event type is displayed:

FieldDefaultWhen applied
negativeColorRedDamage received (Health.OnDamageApplied).
positiveColorBlueHealing or stamina gain (PlayerStamina.OnValueChanged with a positive delta).
blockedColorGreenBlocked attack (Health.OnDamageBlocked). Displays a "Blocked" label instead of a number.

Step 3 — Enemy HUD

Enemy HUD components are typically placed on a Canvas that is a child of the enemy prefab. Each component wires itself to its sibling EnemyController or Health in Start() — there is no extra setup in the Inspector beyond ensuring they share the same parent hierarchy.

ComponentWhat it showsTrigger
EnemyHealthBarCurrent HP as a text label.Health.OnHealthUpdated
EnemyActionSequencePanelGrid of all action icons and loop counts. Visible only on mouse hover.Populated on initialization.
EnemyInstructionIndicatorAnimated icon that switches between actions as the enemy executes.EnemyController.OnStart / OnActionChange / OnEnd

Step 4 — Inventory Window

InventoryWindow is a singleton accessed at runtime via InventoryWindow.current. Open and close it from any script:

InventoryWindow.current.Open();
InventoryWindow.current.Close();

The window manages three categories of child widgets. Wire them up in the Inspector before entering Play Mode:

  1. Stats array — Add one StatSlot entry per stat you want visible. Each entry pairs a Stat asset with a TMP_Text label; the window writes the current total to that label on Refresh().
  2. Equipment slots — Place one EquipmentSlotLayout per slot type (Weapon, Shield, Helmet, Armor, Boots) and set the matching Equipment.Type on each in the Inspector. Hovering an occupied slot shows a floating tooltip with stats and effects.
  3. Item slots — A pool of ItemSlotLayout widgets. The window fills them automatically from the inventory on Open() and Refresh().

Call Refresh() manually if the inventory changes while the window is already visible.

Step 5 — Win Screen & Options Menu

WinScreenController subscribes to LevelManager.OnLevelCompleted and opens itself — no manual trigger is needed. GameOptionsMenu must be opened from a button using a standard UnityEvent or from code:

GetComponent<GameOptionsMenu>().Open();
GetComponent<GameOptionsMenu>().Close();

Both extend Window, so they play the openSound / closeSound clips assigned in the Inspector automatically.

Step 6 — Notifications

Show a generic toast from any MonoBehaviour:

NotificationLayout notificationPrefab; // assign in Inspector
notificationPrefab.CreateInstance(icon, "Your message here", transform);

The notification slides in, holds for 7 seconds, then dismisses itself. The parent argument controls where it is placed in the Canvas hierarchy; pass null to use the prefab's default parent.

Queue an equipment announcement from anywhere — including across scene loads:

EquipmentNotification.AddEquipment(equipment);

If a notification is already on screen, the new one enters the queue and appears automatically once the current one is dismissed.

Step 7 — Custom Windows

Subclass Window to add any new modal panel to your scene:

public class MyPanel : Window
{
    public override void Open()
    {
        // run custom logic before the panel appears
        base.Open();
    }

    public override void Close()
    {
        base.Close();
        // run custom logic after the panel hides
    }
}

Assign openSound and closeSound clips in the Inspector for automatic SFX. If no AudioSource is assigned the window opens and closes silently.