Zabiju je

This commit is contained in:
2026-04-26 13:30:33 +02:00
parent 208696487e
commit 700e6bfbfc
143 changed files with 11027 additions and 1298 deletions

View File

@@ -0,0 +1,318 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
/// <summary>
/// Programmatically builds the complete in-game HUD inside the InGame canvas (Client.unity).
///
/// Call BuildNow() explicitly from GameManager.OnSceneLoaded BEFORE BindClientScene(),
/// so that GameManager_UI can find the newly created elements by name.
///
/// Named GameObjects created as direct children of InGame canvas (required by Transform.Find):
/// • ActionButton — Button + TMP child; shown/hidden by GameManager_Tasks.UpdateProximity()
/// • SabotagePanel — warning banner at top (contains "SabotageTimer" TMP_Text)
/// • MeetingPanel — voting/meeting overlay (populated by GameManager_UI.ShowMeetingPanel)
/// • GameEndPanel — end-of-game overlay (contains "GameEndText" TMP_Text)
///
/// Named TMP_Text descendants (found by GameManager_UI.FindTMP — any depth):
/// • KillCooldown — shown to impostors during kill cooldown
/// • TaskList — crewmate task names
/// • TaskProgress — global task completion "X/Y tasks"
/// • SabotageTimer — countdown inside SabotagePanel
/// • GameEndText — win/lose result text inside GameEndPanel
/// • (Role already exists in the scene)
///
/// Additional elements managed by this script:
/// • RecenterBtn — calls MapCameraController.Instance.Recenter()
/// </summary>
public class InGameHUDBuilder : MonoBehaviour
{
// ── Color palette ─────────────────────────────────────────────────────────
private static readonly Color C_BG = new Color(0.05f, 0.06f, 0.12f, 0.80f);
private static readonly Color C_BAR_BG = new Color(0.03f, 0.04f, 0.08f, 0.90f);
private static readonly Color C_ACCENT = new Color(0.20f, 0.60f, 1.00f, 1.00f);
private static readonly Color C_GREEN = new Color(0.18f, 0.75f, 0.30f, 1.00f);
private static readonly Color C_RED = new Color(0.76f, 0.19f, 0.19f, 1.00f);
private static readonly Color C_ORANGE = new Color(0.95f, 0.55f, 0.10f, 1.00f);
private bool _built;
// ── Entry points ──────────────────────────────────────────────────────────
/// <summary>Called from GameManager.OnSceneLoaded before BindClientScene.</summary>
public void BuildNow()
{
if (_built) return;
_built = true;
Build();
}
void Start()
{
if (!_built) Build(); // safety fallback
}
// ── Build ─────────────────────────────────────────────────────────────────
void Build()
{
var rt = GetComponent<RectTransform>();
if (rt == null) return;
// ── Top bar: role is already in scene, add kill-cooldown ─────────────
BuildTopBar(rt);
// ── Right task panel ──────────────────────────────────────────────────
BuildTaskPanel(rt);
// ── Task progress (above bottom bar) ─────────────────────────────────
BuildTaskProgress(rt);
// ── Bottom bar: action button + recenter ──────────────────────────────
BuildBottomBar(rt);
// ── Action button (DIRECT child — Transform.Find requirement) ─────────
BuildActionButton(rt);
// ── Sabotage panel (DIRECT child) ─────────────────────────────────────
BuildSabotagePanel(rt);
// ── Meeting panel (DIRECT child) ──────────────────────────────────────
BuildMeetingPanel(rt);
// ── Game-end panel (DIRECT child) ─────────────────────────────────────
BuildGameEndPanel(rt);
}
// ── Section builders ──────────────────────────────────────────────────────
void BuildTopBar(RectTransform parent)
{
// Thin semi-transparent header at very top
var bar = AddChild("_TopBar", parent);
Anchor(bar, new Vector2(0f, 1f), new Vector2(1f, 1f));
bar.sizeDelta = new Vector2(0f, 90f);
bar.anchoredPosition = new Vector2(0f, 0f);
bar.pivot = new Vector2(0.5f, 1f);
AddImage(bar.gameObject, C_BAR_BG);
// Kill cooldown (right side) — starts hidden
var cd = AddChild("KillCooldown", bar);
Anchor(cd, new Vector2(0.5f, 0f), new Vector2(1f, 1f));
cd.offsetMin = new Vector2(0f, 6f);
cd.offsetMax = new Vector2(-12f, -6f);
var cdTmp = cd.gameObject.AddComponent<TextMeshProUGUI>();
cdTmp.text = "";
cdTmp.fontSize = 32;
cdTmp.color = C_ORANGE;
cdTmp.fontStyle = FontStyles.Bold;
cdTmp.alignment = TextAlignmentOptions.MidlineRight;
cd.gameObject.SetActive(false);
}
void BuildTaskPanel(RectTransform parent)
{
// Right-side floating panel (always visible during game)
var panel = AddChild("_TaskPanel", parent);
Anchor(panel, new Vector2(1f, 0.35f), new Vector2(1f, 0.88f));
panel.pivot = new Vector2(1f, 0.5f);
panel.sizeDelta = new Vector2(280f, 0f);
panel.anchoredPosition = Vector2.zero;
AddImage(panel.gameObject, C_BG);
// "MY TASKS" header
var hdr = AddChild("_Header", panel);
Anchor(hdr, new Vector2(0f, 1f), new Vector2(1f, 1f));
hdr.pivot = new Vector2(0.5f, 1f);
hdr.sizeDelta = new Vector2(0f, 44f);
hdr.anchoredPosition = Vector2.zero;
AddImage(hdr.gameObject, C_ACCENT * new Color(1, 1, 1, 0.6f));
var hdrTmp = AddTextChild(hdr, "_HeaderTxt", "MY TASKS", 26, FontStyles.Bold, TextAlignmentOptions.Center);
hdrTmp.color = Color.white;
// Task list body
var body = AddChild("TaskList", panel);
Anchor(body, new Vector2(0f, 0f), new Vector2(1f, 1f));
body.offsetMin = new Vector2(8f, 8f);
body.offsetMax = new Vector2(-8f, -48f);
var taskTmp = body.gameObject.AddComponent<TextMeshProUGUI>();
taskTmp.text = "";
taskTmp.fontSize = 22;
taskTmp.color = Color.white;
taskTmp.alignment = TextAlignmentOptions.TopLeft;
}
void BuildTaskProgress(RectTransform parent)
{
var prog = AddChild("TaskProgress", parent);
Anchor(prog, new Vector2(0f, 0f), new Vector2(1f, 0f));
prog.pivot = new Vector2(0.5f, 0f);
prog.sizeDelta = new Vector2(-20f, 40f);
prog.anchoredPosition = new Vector2(0f, 120f); // above bottom bar
var tmp = prog.gameObject.AddComponent<TextMeshProUGUI>();
tmp.text = "";
tmp.fontSize = 28;
tmp.color = Color.white;
tmp.fontStyle = FontStyles.Bold;
tmp.alignment = TextAlignmentOptions.Center;
}
void BuildBottomBar(RectTransform parent)
{
var bar = AddChild("_BottomBar", parent);
Anchor(bar, new Vector2(0f, 0f), new Vector2(1f, 0f));
bar.pivot = new Vector2(0.5f, 0f);
bar.sizeDelta = new Vector2(0f, 110f);
bar.anchoredPosition = Vector2.zero;
AddImage(bar.gameObject, C_BAR_BG);
// Recenter button (bottom-right of bar)
var recBtn = AddChild("_RecenterBtn", bar);
Anchor(recBtn, new Vector2(0.82f, 0.08f), new Vector2(0.98f, 0.92f));
var recBg = AddImage(recBtn.gameObject, C_ACCENT);
var recButton = recBtn.gameObject.AddComponent<Button>();
var recColors = recButton.colors;
recColors.pressedColor = new Color(0.1f, 0.4f, 0.8f);
recButton.colors = recColors;
recButton.targetGraphic = recBg;
recButton.onClick.AddListener(() => MapCameraController.Instance?.Recenter());
var recTxt = AddTextChild(recBtn, "_RecTxt", "⊙", 42, FontStyles.Bold, TextAlignmentOptions.Center);
recTxt.color = Color.white;
}
void BuildActionButton(RectTransform parent)
{
// MUST be a DIRECT child so Transform.Find("ActionButton") works
var btn = AddChild("ActionButton", parent);
Anchor(btn, new Vector2(0.15f, 0f), new Vector2(0.80f, 0f));
btn.pivot = new Vector2(0.5f, 0f);
btn.sizeDelta = new Vector2(0f, 90f);
btn.anchoredPosition = new Vector2(0f, 12f);
var bg = AddImage(btn.gameObject, C_GREEN);
var button = btn.gameObject.AddComponent<Button>();
var colors = button.colors;
colors.normalColor = C_GREEN;
colors.pressedColor = new Color(0.12f, 0.55f, 0.22f);
button.colors = colors;
button.targetGraphic = bg;
// TMP child named "Text" so GetComponentInChildren<TMP_Text> finds it
var txtRt = AddChild("Text", btn);
Stretch(txtRt);
var tmp = txtRt.gameObject.AddComponent<TextMeshProUGUI>();
tmp.text = "ACTION";
tmp.fontSize = 44;
tmp.fontStyle = FontStyles.Bold;
tmp.color = Color.white;
tmp.alignment = TextAlignmentOptions.Center;
btn.gameObject.SetActive(false); // hidden until proximity detected
}
void BuildSabotagePanel(RectTransform parent)
{
// DIRECT child
var panel = AddChild("SabotagePanel", parent);
Anchor(panel, new Vector2(0f, 0.88f), new Vector2(1f, 1f));
panel.offsetMin = new Vector2(0f, -10f);
panel.offsetMax = new Vector2(0f, -80f);
AddImage(panel.gameObject, C_RED * new Color(1, 1, 1, 0.88f));
var timer = AddChild("SabotageTimer", panel);
Stretch(timer);
var tmp = timer.gameObject.AddComponent<TextMeshProUGUI>();
tmp.text = "SABOTAGE!";
tmp.fontSize = 48;
tmp.fontStyle = FontStyles.Bold;
tmp.color = Color.white;
tmp.alignment = TextAlignmentOptions.Center;
panel.gameObject.SetActive(false);
}
void BuildMeetingPanel(RectTransform parent)
{
// DIRECT child — populated by GameManager_UI.ShowMeetingPanel at runtime
var panel = AddChild("MeetingPanel", parent);
Anchor(panel, new Vector2(0.05f, 0.10f), new Vector2(0.95f, 0.90f));
AddImage(panel.gameObject, new Color(0.04f, 0.05f, 0.14f, 0.96f));
var title = AddChild("_MeetingTitle", panel);
Anchor(title, new Vector2(0f, 0.85f), new Vector2(1f, 1f));
var titleTmp = title.gameObject.AddComponent<TextMeshProUGUI>();
titleTmp.text = "EMERGENCY MEETING";
titleTmp.fontSize = 44;
titleTmp.fontStyle = FontStyles.Bold;
titleTmp.color = C_ORANGE;
titleTmp.alignment = TextAlignmentOptions.Center;
panel.gameObject.SetActive(false);
}
void BuildGameEndPanel(RectTransform parent)
{
// DIRECT child, full-screen overlay
var panel = AddChild("GameEndPanel", parent);
Stretch(panel);
AddImage(panel.gameObject, new Color(0f, 0f, 0f, 0.85f));
var txt = AddChild("GameEndText", panel);
Stretch(txt);
var tmp = txt.gameObject.AddComponent<TextMeshProUGUI>();
tmp.text = "";
tmp.fontSize = 72;
tmp.fontStyle = FontStyles.Bold;
tmp.color = Color.white;
tmp.alignment = TextAlignmentOptions.Center;
panel.gameObject.SetActive(false);
}
// ── Helpers ───────────────────────────────────────────────────────────────
RectTransform AddChild(string name, RectTransform parent)
{
var go = new GameObject(name);
var rt = go.AddComponent<RectTransform>();
rt.SetParent(parent, false);
rt.localScale = Vector3.one;
return rt;
}
Image AddImage(GameObject go, Color color)
{
var img = go.AddComponent<Image>();
img.color = color;
return img;
}
TextMeshProUGUI AddTextChild(RectTransform parent, string name, string text,
float size, FontStyles style, TextAlignmentOptions align)
{
var rt = AddChild(name, parent);
Stretch(rt);
var tmp = rt.gameObject.AddComponent<TextMeshProUGUI>();
tmp.text = text;
tmp.fontSize = size;
tmp.fontStyle = style;
tmp.alignment = align;
tmp.color = Color.white;
return tmp;
}
void Anchor(RectTransform rt, Vector2 min, Vector2 max)
{
rt.anchorMin = min;
rt.anchorMax = max;
rt.offsetMin = Vector2.zero;
rt.offsetMax = Vector2.zero;
}
void Stretch(RectTransform rt)
{
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.offsetMin = Vector2.zero;
rt.offsetMax = Vector2.zero;
}
}