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]>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user