using System.Collections; using UnityEngine; namespace TKS { /// 유닛 도형 표시: 몸통 원 · 병종 글자 · 이름 · HP 바 · 선택/표적 링 · 보스 테두리 · 창병 대기 반경. public class UnitView : MonoBehaviour { public static readonly Color PlayerColor = new Color(0.25f, 0.55f, 0.95f); public static readonly Color EnemyColor = new Color(0.9f, 0.32f, 0.3f); Unit unit; SpriteRenderer body; SpriteRenderer bossRing; SpriteRenderer selectRing; SpriteRenderer highlightRing; SpriteRenderer overwatchArea; SpriteRenderer hpBg; SpriteRenderer hpFill; TextMesh mark; TextMesh nameLabel; TextMesh badge; Color baseColor; Coroutine flash; const float HpBarWidth = 1.0f; public void Build(Unit u) { unit = u; foreach (Transform c in transform) Destroy(c.gameObject); baseColor = u.Faction == Faction.Player ? PlayerColor : EnemyColor; float d = u.Radius * 2f; // 창병 대기 반경 표시(창병만 · 발동 중에만 오브젝트 통째로 켬) overwatchArea = ProceduralSprites.NewSprite(transform, "OverwatchArea", ProceduralSprites.Circle, new Color(0.3f, 0.65f, 1f, 0.16f), u.Type == UnitType.Spear ? u.AttackRange * 2f : 0f, -6); var owRing = ProceduralSprites.NewSprite(overwatchArea.transform, "Ring", ProceduralSprites.Ring, new Color(0.5f, 0.8f, 1f, 0.6f), 1f, -5); owRing.transform.localScale = Vector3.one; overwatchArea.gameObject.SetActive(false); if (u.IsBoss) { bossRing = ProceduralSprites.NewSprite(transform, "BossRing", ProceduralSprites.Circle, new Color(1f, 0.85f, 0.3f), d + 0.16f, -1); } body = ProceduralSprites.NewSprite(transform, "Body", ProceduralSprites.Circle, baseColor, d, 0); selectRing = ProceduralSprites.NewSprite(transform, "SelectRing", ProceduralSprites.Ring, new Color(1f, 0.95f, 0.4f), d + 0.28f, 1); selectRing.enabled = false; highlightRing = ProceduralSprites.NewSprite(transform, "HighlightRing", ProceduralSprites.Ring, new Color(1f, 0.5f, 0.15f), d + 0.28f, 1); highlightRing.enabled = false; hpBg = ProceduralSprites.NewSprite(transform, "HpBg", ProceduralSprites.Square, new Color(0.08f, 0.08f, 0.08f, 0.9f), 1f, 2); hpBg.transform.localPosition = new Vector3(0f, u.Radius + 0.22f, 0f); hpBg.transform.localScale = new Vector3(HpBarWidth, 0.12f, 1f); hpFill = ProceduralSprites.NewSprite(transform, "HpFill", ProceduralSprites.Square, new Color(0.35f, 0.9f, 0.35f), 1f, 3); hpFill.transform.localPosition = hpBg.transform.localPosition; hpFill.transform.localScale = new Vector3(HpBarWidth, 0.12f, 1f); mark = TextUtil.CreateWorldText(transform, UnitTypeInfo.Mark(u.Type), u.Radius * 1.1f, Color.white, 4); nameLabel = TextUtil.CreateWorldText(transform, u.DisplayName, 0.26f, new Color(0.95f, 0.95f, 0.9f), 4); nameLabel.transform.localPosition = new Vector3(0f, -u.Radius - 0.22f, 0f); badge = TextUtil.CreateWorldText(transform, "추가 이동", 0.22f, new Color(1f, 0.95f, 0.4f), 5); badge.transform.localPosition = new Vector3(0f, u.Radius + 0.46f, 0f); badge.gameObject.SetActive(false); Refresh(); } public void Refresh() { if (unit == null || hpFill == null) return; float ratio = unit.MaxHp > 0 ? Mathf.Clamp01((float)unit.Hp / unit.MaxHp) : 0f; hpFill.transform.localScale = new Vector3(HpBarWidth * ratio, 0.12f, 1f); hpFill.transform.localPosition = new Vector3(-HpBarWidth * 0.5f + HpBarWidth * ratio * 0.5f, hpBg.transform.localPosition.y, 0f); hpFill.color = ratio > 0.5f ? new Color(0.35f, 0.9f, 0.35f) : (ratio > 0.25f ? new Color(0.95f, 0.8f, 0.2f) : new Color(0.95f, 0.3f, 0.2f)); bool dim = unit.Faction == Faction.Player && unit.ActedThisTurn; var c = baseColor; if (dim) c = Color.Lerp(baseColor, new Color(0.3f, 0.3f, 0.32f), 0.6f); if (flash == null) body.color = c; mark.color = dim ? new Color(1f, 1f, 1f, 0.6f) : Color.white; bool ow = unit.Overwatch && unit.Type == UnitType.Spear && unit.IsAlive; if (overwatchArea.gameObject.activeSelf != ow) overwatchArea.gameObject.SetActive(ow); badge.gameObject.SetActive(unit.BonusMoveAvailable && unit.IsAlive); } public void SetSelected(bool on) { if (selectRing != null) selectRing.enabled = on; } public void SetHighlight(bool on) { if (highlightRing != null) highlightRing.enabled = on; } public void OnHit() { if (!isActiveAndEnabled) return; if (flash != null) StopCoroutine(flash); flash = StartCoroutine(FlashRoutine()); } IEnumerator FlashRoutine() { body.color = Color.white; float t = 0f; while (t < 0.18f) { t += Time.deltaTime; yield return null; } flash = null; Refresh(); } public void PlayDeath() { if (!isActiveAndEnabled) return; StartCoroutine(DeathRoutine()); } IEnumerator DeathRoutine() { selectRing.enabled = false; highlightRing.enabled = false; overwatchArea.gameObject.SetActive(false); float t = 0f; const float dur = 0.45f; Vector3 s0 = transform.localScale; while (t < dur) { t += Time.deltaTime; float k = Mathf.Clamp01(t / dur); transform.localScale = s0 * (1f - 0.5f * k); var c = body.color; c.a = 1f - k; body.color = c; yield return null; } unit.gameObject.SetActive(false); } } }