using UnityEngine;
namespace TKS
{
///
/// 슬링샷 방향 결정 UI — IB(쿠로네코) GameTouchArrow 이식(PD 2026-11-10 「IB 와 같이 슬링샷 조작 시 방향 결정 UI 등을 그대로 이식」).
/// 프리팹 = Resources/Fx/TKS_Fx_IB_GameArrow(원본 Assets/VFX/IB/AssetResources/Game/GameArrow · 사본 = Tools/make_ib_fx_copies.cs · IB 스크립트 제거).
/// IB 와 같은 동작: 누르면(Ready) 유닛 둘레에 고리 1개 + 퍼지는 고리 3개(3초 동안 0 → 1.3배 · 투명해짐 · 1초 간격 · 반복) ·
/// 당기면 화살표가 쏠 방향으로 돌고(정면 +Y) 당긴 세기만큼 길어짐(가로 0.8 + v × 0.2 · 세로 v · v = 0.5~1.5) · 화살 끝이 전장 밖이면 안으로 밀어 넣음 · 놓으면(End) 숨김.
/// IB 세기 v = 당긴 거리 × 0.6 → 이 게임은 슬링샷 최대 거리 대비 비율로 0.5~1.5 에 맞춘다. 색 = IB 공격 종류 3(하늘색 · 프리팹 기본값).
///
public class IbAimArrow : MonoBehaviour
{
public const string PrefabName = "TKS_Fx_IB_GameArrow";
/// IB GameArrow 공격 종류 3 색(하늘색 · 원본 프리팹 color[2]).
static readonly Color RingColor = new Color(0.468f, 0.866f, 0.897f, 1f);
const float RingPulseSeconds = 3f;
const float RingPulseScale = 1.3f;
const float RingStagger = 1f;
/// 바닥 고리 정렬(사거리 원 −10·−9 와 같은 바닥 층) · 화살표 = 조준선과 같은 10.
const int RingOrder = -9;
const int ArrowOrder = 10;
Transform root;
SpriteRenderer arrow;
Transform arrowTip;
SpriteRenderer ring;
SpriteRenderer[] pulses = new SpriteRenderer[0];
float readyTime;
bool ready;
Board board;
public bool Ready
{
get { return ready; }
}
public bool ArrowVisible
{
get { return arrow != null && arrow.gameObject.activeSelf && ready; }
}
public void Init(Board b)
{
board = b;
var prefab = SkillVfx.LoadFx(PrefabName);
if (prefab == null) return;
var go = Instantiate(prefab, transform);
go.name = PrefabName;
root = go.transform;
foreach (var sr in go.GetComponentsInChildren(true))
{
if (sr.name == "arrow") arrow = sr;
else if (sr.name == "ring01") ring = sr;
}
var list = new System.Collections.Generic.List();
foreach (var n in new[] { "ring02-01", "ring02-02", "ring02-03" })
{
var t = root.Find(n);
if (t != null && t.GetComponent() != null) list.Add(t.GetComponent());
}
pulses = list.ToArray();
int ringOrder = Mathf.RoundToInt(IbUi.Num("order_ground", RingOrder));
if (arrow != null)
{
arrowTip = arrow.transform.Find("object");
arrow.sortingOrder = Mathf.RoundToInt(IbUi.Num("order_arrow", ArrowOrder));
}
if (ring != null)
{
ring.sortingOrder = ringOrder;
ring.color = RingColor;
}
foreach (var p in pulses) p.sortingOrder = ringOrder;
go.SetActive(false);
}
/// IB Ready: 유닛을 누른 순간 — 고리 표시 · 화살표는 당길 때까지 숨김.
public void Begin(Unit u)
{
if (root == null || u == null) return;
ready = true;
readyTime = Time.time;
root.gameObject.SetActive(true);
Place(u);
if (arrow != null) arrow.gameObject.SetActive(false);
}
///
/// 유닛 크기에 맞춰 놓기 — IB 와 같은 비율(PD 2026-11-10 「IB 와 화살표 크기도 다름」): 배율 = 이 게임 유닛 반지름 / IB 유닛 반지름 0.496(표 ib_ui.csv) ·
/// 그러면 고리 지름 = 반지름 × 5.4 · 화살표 = 반지름 × 5.9~17.8 길이(IB 실측 · 화살 그림 피벗 y 0.3 = 유닛 가운데).
///
void Place(Unit u)
{
root.position = new Vector3(u.Position.x, u.Position.y, 0f);
float k = IbUi.Scale(u);
root.localScale = new Vector3(k, k, 1f);
}
///
/// 당기는 중: launch = 쏠 방향·거리(월드 · 목표점 − 유닛) — IB SetTouchArrowScale 그대로: IB 월드로 바꾼 당김 × 0.6 = 세기 s(0.5~1.5) ·
/// 가로 0.8 + 0.2 s · 세로 s · 당김이 IB 취소 거리(0.5) 안이면 화살표 숨김(고리만).
///
public void Aim(Unit u, Vector2 launch)
{
if (root == null || u == null) return;
if (!ready) Begin(u);
Place(u);
if (arrow == null) return;
float dragIb = launch.magnitude / Mathf.Max(0.001f, IbUi.Scale(u));
bool on = dragIb >= IbUi.Num("arrow_cancel", 0.5f);
if (arrow.gameObject.activeSelf != on) arrow.gameObject.SetActive(on);
if (!on) return;
arrow.transform.localPosition = Vector3.zero;
arrow.transform.rotation = Quaternion.FromToRotation(Vector3.up, new Vector3(launch.x, launch.y, 0f));
float v = Mathf.Clamp(dragIb * IbUi.Num("arrow_drag_k", 0.6f), IbUi.Num("arrow_s_min", 0.5f), IbUi.Num("arrow_s_max", 1.5f));
arrow.transform.localScale = new Vector3(0.8f + v * 0.2f, v, 1f);
// IB LateUpdate: 화살 끝이 벽(전장 밖)을 넘으면 화살 전체를 안으로 밀어 넣음
if (board != null && arrowTip != null)
{
Vector2 tip = arrowTip.position;
Vector2 inside = board.ClampInside(tip, 0f);
if ((inside - tip).sqrMagnitude > 1e-6f) arrow.transform.position += (Vector3)(inside - tip);
}
}
/// IB End: 놓거나 취소 — 모두 숨김.
public void End()
{
ready = false;
if (root != null) root.gameObject.SetActive(false);
}
void Update()
{
if (!ready || root == null) return;
float t = Time.time - readyTime;
for (int i = 0; i < pulses.Length; i++)
{
float local = t - i * RingStagger;
var p = pulses[i];
if (local < 0f)
{
p.transform.localScale = Vector3.zero;
continue;
}
float k = (local % RingPulseSeconds) / RingPulseSeconds;
p.transform.localScale = new Vector3(RingPulseScale * k, RingPulseScale * k, 1f);
var c = RingColor;
c.a = 1f - k;
p.color = c;
}
}
}
}