144 lines
5.9 KiB
C#
144 lines
5.9 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
namespace TKS
|
|
{
|
|
/// <summary>유닛 도형 표시: 몸통 원 · 병종 글자 · 이름 · HP 바 · 선택/표적 링 · 보스 테두리 · 창병 대기 반경.</summary>
|
|
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.AttackRange * 2f, -6);
|
|
overwatchArea.enabled = false;
|
|
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;
|
|
|
|
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;
|
|
|
|
overwatchArea.enabled = unit.Overwatch;
|
|
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.enabled = 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);
|
|
}
|
|
}
|
|
}
|