ThreeKingdomsSlingshot/Assets/Scripts/Runtime/Fx.cs

112 lines
4.2 KiB
C#

using System;
using System.Collections;
using UnityEngine;
namespace TKS
{
/// <summary>간단한 연출(이동 트윈·돌진·화살·피해 숫자). 코루틴 실행자는 BattleManager.</summary>
public static class Fx
{
public static MonoBehaviour Runner;
public static Coroutine Run(IEnumerator routine)
{
if (Runner == null) return null;
return Runner.StartCoroutine(routine);
}
public static IEnumerator Wait(float seconds)
{
float t = 0f;
while (t < seconds)
{
t += Time.deltaTime;
yield return null;
}
}
/// <summary>from → to 이동(기본 = 감속 · easeOut false = 등속 → 부딪히는 순간까지 속도를 유지). onDistance 에는 지금까지 지나온 거리를 넘긴다.</summary>
public static IEnumerator MoveAlong(Transform tr, Vector2 from, Vector2 to, float speed, Action<float> onDistance, bool easeOut = true)
{
float total = Vector2.Distance(from, to);
if (total < 1e-4f) yield break;
float duration = Mathf.Max(0.12f, total / Mathf.Max(0.1f, speed));
float el = 0f;
while (el < duration)
{
el += Time.deltaTime;
float k = Mathf.Clamp01(el / duration);
float e = easeOut ? 1f - (1f - k) * (1f - k) : k;
var p = Vector2.Lerp(from, to, e);
tr.position = new Vector3(p.x, p.y, 0f);
if (onDistance != null) onDistance(e * total);
yield return null;
}
tr.position = new Vector3(to.x, to.y, 0f);
if (onDistance != null) onDistance(total);
}
/// <summary>근접 공격 돌진(짧게 찌르고 복귀).</summary>
public static IEnumerator Lunge(Unit a, Vector2 toward)
{
Vector2 start = a.Position;
Vector2 dir = (toward - start);
if (dir.sqrMagnitude < 1e-4f) yield break;
dir.Normalize();
Vector2 peak = start + dir * 0.3f;
yield return MoveAlong(a.transform, start, peak, 6f, null);
yield return MoveAlong(a.transform, peak, start, 4f, null);
a.Position = start;
}
/// <summary>화살(가늘고 긴 사각형) 날리기.</summary>
public static IEnumerator Arrow(Vector2 from, Vector2 to)
{
var go = new GameObject("Arrow");
var sr = go.AddComponent<SpriteRenderer>();
sr.sprite = ProceduralSprites.Square;
sr.color = new Color(1f, 0.95f, 0.75f);
sr.sortingOrder = 8;
Vector2 d = to - from;
float ang = Mathf.Atan2(d.y, d.x) * Mathf.Rad2Deg;
go.transform.rotation = Quaternion.Euler(0f, 0f, ang);
go.transform.localScale = new Vector3(0.5f, 0.06f, 1f);
float dur = Mathf.Max(0.12f, d.magnitude / 14f);
float t = 0f;
while (t < dur)
{
t += Time.deltaTime;
var p = Vector2.Lerp(from, to, Mathf.Clamp01(t / dur));
go.transform.position = new Vector3(p.x, p.y, 0f);
yield return null;
}
UnityEngine.Object.Destroy(go);
}
public static void Popup(Vector2 pos, string text, Color color)
{
Run(PopupRoutine(pos, text, color));
}
static IEnumerator PopupRoutine(Vector2 pos, string text, Color color)
{
var tm = TextUtil.CreateWorldText(null, text, 0.42f, color, 20);
tm.gameObject.name = "Popup";
var tr = tm.transform;
float t = 0f;
const float dur = 0.75f;
while (t < dur)
{
t += Time.deltaTime;
float k = Mathf.Clamp01(t / dur);
tr.position = new Vector3(pos.x, pos.y + 0.55f + 0.7f * k, 0f);
var c = color;
c.a = 1f - k * k;
tm.color = c;
yield return null;
}
UnityEngine.Object.Destroy(tm.gameObject);
}
}
}