using UnityEngine; using UnityEngine.UI; /// /// Шкала здоровья Босса вверху посередине экрана. /// Показывает имя босса, текущее/максимальное здоровье и плавное заполнение полосы. /// public class BossHealthBarUI : MonoBehaviour { private static BossHealthBarUI _instance; public static BossHealthBarUI Instance { get { if (_instance == null) _instance = FindAnyObjectByType(FindObjectsInactive.Include); return _instance; } } [Header("Элементы интерфейса")] public GameObject rootPanel; public Text bossTitleText; public Text bossSubText; public Image fillBar; public Text healthValueText; public CanvasGroup canvasGroup; private float targetFill = 1f; private float currentFill = 1f; private bool isVisible = false; public static BossHealthBarUI Create(Transform hudCanvas) { var old = hudCanvas.Find("BossHealthBarPanel"); if (old != null) DestroyImmediate(old.gameObject); Font defaultFont = Resources.GetBuiltinResource("LegacyRuntime.ttf"); // 1. Корневой объект GameObject root = new GameObject("BossHealthBarPanel", typeof(RectTransform), typeof(CanvasGroup)); root.transform.SetParent(hudCanvas, false); RectTransform rootRt = root.GetComponent(); rootRt.anchorMin = new Vector2(0.5f, 1.0f); rootRt.anchorMax = new Vector2(0.5f, 1.0f); rootRt.pivot = new Vector2(0.5f, 1.0f); rootRt.anchoredPosition = new Vector2(0f, -22f); rootRt.sizeDelta = new Vector2(560f, 62f); // 2. Фон контейнера Image bgImg = root.AddComponent(); bgImg.color = new Color(0.04f, 0.04f, 0.05f, 0.92f); Outline outline = root.AddComponent(); outline.effectColor = new Color(1.0f, 0.25f, 0.25f, 0.65f); outline.effectDistance = new Vector2(1.5f, -1.5f); // 3. Заголовок босса GameObject titleObj = new GameObject("BossTitle", typeof(RectTransform), typeof(CanvasRenderer), typeof(Text)); titleObj.transform.SetParent(root.transform, false); RectTransform titleRt = titleObj.GetComponent(); titleRt.anchorMin = new Vector2(0f, 0.62f); titleRt.anchorMax = new Vector2(1f, 1.0f); titleRt.offsetMin = new Vector2(15f, 0f); titleRt.offsetMax = new Vector2(-15f, -4f); Text titleText = titleObj.GetComponent(); titleText.font = defaultFont; titleText.fontSize = 15; titleText.fontStyle = FontStyle.Bold; titleText.alignment = TextAnchor.MiddleCenter; titleText.color = new Color(1.0f, 0.3f, 0.3f, 1.0f); titleText.text = "ТИП-0: АЛЬФА-МУТАНТ (ПАТРИАРХ)"; // 4. Фон полосы здоровья GameObject barBgObj = new GameObject("BarBackground", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image)); barBgObj.transform.SetParent(root.transform, false); RectTransform barBgRt = barBgObj.GetComponent(); barBgRt.anchorMin = new Vector2(0f, 0.16f); barBgRt.anchorMax = new Vector2(1f, 0.54f); barBgRt.offsetMin = new Vector2(14f, 0f); barBgRt.offsetMax = new Vector2(-14f, 0f); Image barBgImg = barBgObj.GetComponent(); barBgImg.color = new Color(0.18f, 0.05f, 0.05f, 0.95f); // 5. Заполнение полосы (красный градиент) GameObject fillObj = new GameObject("BarFill", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image)); fillObj.transform.SetParent(barBgObj.transform, false); RectTransform fillRt = fillObj.GetComponent(); fillRt.anchorMin = Vector2.zero; fillRt.anchorMax = Vector2.one; fillRt.sizeDelta = Vector2.zero; Image fillImg = fillObj.GetComponent(); fillImg.type = Image.Type.Filled; fillImg.fillMethod = Image.FillMethod.Horizontal; fillImg.fillOrigin = (int)Image.OriginHorizontal.Left; fillImg.color = new Color(0.95f, 0.2f, 0.2f, 1.0f); // 6. Текст числового значения HP GameObject hpTxtObj = new GameObject("HealthText", typeof(RectTransform), typeof(CanvasRenderer), typeof(Text)); hpTxtObj.transform.SetParent(barBgObj.transform, false); RectTransform hpTxtRt = hpTxtObj.GetComponent(); hpTxtRt.anchorMin = Vector2.zero; hpTxtRt.anchorMax = Vector2.one; hpTxtRt.sizeDelta = Vector2.zero; Text hpTxt = hpTxtObj.GetComponent(); hpTxt.font = defaultFont; hpTxt.fontSize = 13; hpTxt.fontStyle = FontStyle.Bold; hpTxt.alignment = TextAnchor.MiddleCenter; hpTxt.color = Color.white; hpTxt.text = "500 / 500"; BossHealthBarUI barUI = root.AddComponent(); barUI.rootPanel = root; barUI.bossTitleText = titleText; barUI.fillBar = fillImg; barUI.healthValueText = hpTxt; barUI.canvasGroup = root.GetComponent(); barUI.canvasGroup.alpha = 0f; barUI.canvasGroup.blocksRaycasts = false; barUI.canvasGroup.interactable = false; root.SetActive(false); return barUI; } private void Awake() { _instance = this; if (canvasGroup == null) canvasGroup = GetComponent(); } private void Update() { // Плавное заполнение полосы currentFill = Mathf.MoveTowards(currentFill, targetFill, 2.5f * Time.deltaTime); if (fillBar != null) { fillBar.fillAmount = currentFill; } // Плавный альфа-фейд if (canvasGroup != null) { float targetAlpha = isVisible ? 1f : 0f; canvasGroup.alpha = Mathf.MoveTowards(canvasGroup.alpha, targetAlpha, 4f * Time.deltaTime); if (!isVisible && canvasGroup.alpha <= 0.01f && gameObject.activeSelf) { gameObject.SetActive(false); } } } public void ShowBoss(string name, float current, float max) { if (bossTitleText != null) bossTitleText.text = name; targetFill = Mathf.Clamp01(current / max); currentFill = targetFill; if (fillBar != null) fillBar.fillAmount = currentFill; if (healthValueText != null) healthValueText.text = $"{Mathf.CeilToInt(current)} / {Mathf.CeilToInt(max)}"; gameObject.SetActive(true); isVisible = true; } public void UpdateHealth(float current, float max) { targetFill = Mathf.Clamp01(current / max); if (healthValueText != null) healthValueText.text = $"{Mathf.Max(0, Mathf.CeilToInt(current))} / {Mathf.CeilToInt(max)}"; if (current <= 0f) { HideBoss(false); } } public void HideBoss(bool instant = false) { isVisible = false; if (instant) { if (canvasGroup != null) canvasGroup.alpha = 0f; gameObject.SetActive(false); } } }