implemented NPC system and working bartender conversation

This commit is contained in:
2026-08-15 19:02:01 +02:00
parent be63c21e15
commit f89781d78b
18 changed files with 1042 additions and 160 deletions
@@ -0,0 +1,67 @@
using UnityEngine;
namespace NightclubArcadia.Dialogue
{
/// <summary>
/// Shows and hides the dialogue UI *without* deactivating its GameObject.
///
/// SetActive(false) is not a safe way to hide this UI. TextMeshProUGUI
/// resolves its Canvas through Graphic.CacheCanvas, which calls
/// GetComponentsInParent(includeInactive: false) and then requires
/// canvas.isActiveAndEnabled. Once the Canvas GameObject has been
/// deactivated, that lookup yields null, and TMP.GetTextInfo does:
///
/// if (m_canvas == null) m_canvas = this.canvas; // still null
/// GenerateTextMesh(); // m_canvas.worldCamera -> NRE
///
/// GenerateTextMesh dereferences m_canvas unguarded, so the very next line
/// Yarn tries to type throws NullReferenceException. Keeping the hierarchy
/// active and driving a CanvasGroup instead means the cached Canvas
/// reference stays valid across any number of enter/exit dialogue cycles.
/// </summary>
public static class DialogueUIVisibility
{
/// <summary>
/// Makes the dialogue UI visible and interactive. Returns true if the
/// GameObject had to be re-activated (legacy scene state), in which
/// case the caller must wait one frame before rendering text so that
/// TMP's OnEnable can re-cache its Canvas.
/// </summary>
public static bool Show(GameObject dialogueUI) => SetVisible(dialogueUI, true);
/// <summary>
/// Hides the dialogue UI, leaving the hierarchy active. See class docs.
/// </summary>
public static void Hide(GameObject dialogueUI) => SetVisible(dialogueUI, false);
static bool SetVisible(GameObject dialogueUI, bool visible)
{
if (dialogueUI == null)
{
return false;
}
// The UI may still be deactivated by an older saved scene state or
// by code that predates this helper. Recover from that, and tell
// the caller a frame of grace is needed.
var wasReactivated = false;
if (!dialogueUI.activeSelf)
{
dialogueUI.SetActive(true);
wasReactivated = true;
}
var group = dialogueUI.GetComponent<CanvasGroup>();
if (group == null)
{
group = dialogueUI.AddComponent<CanvasGroup>();
}
group.alpha = visible ? 1f : 0f;
group.interactable = visible;
group.blocksRaycasts = visible;
return wasReactivated;
}
}
}