Files
lennartandClaude Opus 5 cba87dcb31 add UI layer: dialogue stream, HUD, player menu, and skills panel
Runtime UI under Scripts/UI: a UIStateController owning menu/dialogue state, a
PlayerControlLock so opening a panel suppresses world input, panel visibility
helpers, and the menu input binding.

Views: the dialogue stream presenter and its options presenter and message row,
the portrait HUD, and the player menu with character, journal, and tab-bar
views. Skills gains SkillsPanelView and SkillRowView, which is why the Skills
asmdef now references UnityEngine.UI.

Prefabs/UI holds the authored canvases (dialogue stream, HUD, player menu) and
their rows. UILayerBootstrap remains a hand-added runtime fallback for scenes
where those prefabs are not instantiated; it deliberately does not auto-spawn.

Editor/UILayerSetup.cs is the one-shot menu that builds and wires those prefabs
into a scene, with UILayerSetupAutoRun reminding after a script reload.

Art/UI/Placeholder carries the placeholder portrait the HUD falls back to.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 19:03:42 +02:00

64 lines
1.6 KiB
C#

using System;
using UnityEngine;
namespace NightclubArcadia.UI
{
/// <summary>
/// Owns the two independent UI state flags — dialogue active and menu open —
/// and raises <see cref="StateChanged"/> so HUD, camera framing, and panels
/// can derive their visibility from a single source of truth.
/// </summary>
public sealed class UIStateController : MonoBehaviour
{
public static UIStateController Instance { get; private set; }
public bool IsDialogueActive { get; private set; }
public bool IsMenuOpen { get; private set; }
/// <summary>Raised after any state change. Subscribers derive their own visibility.</summary>
public event Action StateChanged;
void Awake()
{
if (Instance != null && Instance != this)
{
Debug.LogError($"[{nameof(UIStateController)}] Duplicate instance on '{name}'. Destroying this component.", this);
Destroy(this);
return;
}
Instance = this;
}
void OnDestroy()
{
if (Instance == this)
{
Instance = null;
}
}
public void SetDialogueActive(bool value)
{
if (IsDialogueActive == value)
{
return;
}
IsDialogueActive = value;
StateChanged?.Invoke();
}
public void SetMenuOpen(bool value)
{
if (IsMenuOpen == value)
{
return;
}
IsMenuOpen = value;
StateChanged?.Invoke();
}
}
}