diff --git a/Assets/Scripts/Runtime/ActionResolver.cs b/Assets/Scripts/Runtime/ActionResolver.cs index d7aa20cc..cef5232a 100644 --- a/Assets/Scripts/Runtime/ActionResolver.cs +++ b/Assets/Scripts/Runtime/ActionResolver.cs @@ -54,6 +54,8 @@ namespace TKS if (dist < 0.001f || !u.IsAlive) yield break; Vector2 dir = delta / dist; + // 슬링샷 돌진 중 = 병종 돌진 포즈 1프레임 고정 · 끝나면 대기 (PD 2026-11-05 #1084) + if (u.View != null) u.View.SetCharging(true); switch (u.Type) { case UnitType.Infantry: @@ -69,6 +71,7 @@ namespace TKS yield return ArcherRoutine(u, origin, dir, dist, target, moveOnly, o); break; } + if (u.View != null) u.View.SetCharging(false); } // ---------- 미리보기(드라이런) ---------- diff --git a/Assets/Scripts/Runtime/UnitView.cs b/Assets/Scripts/Runtime/UnitView.cs index 362cbd9c..0032c8e8 100644 --- a/Assets/Scripts/Runtime/UnitView.cs +++ b/Assets/Scripts/Runtime/UnitView.cs @@ -33,6 +33,7 @@ namespace TKS Color baseColor; Coroutine flash; bool aiming; + bool charging; // 슬링샷 돌진(이동) 중 = 돌진 포즈 고정 bool facingBack; // 위를 봄(뒷모습 back_* 세트) · false = 아래를 봄(앞모습 front_*) bool facingLeft; // 왼쪽을 봄(좌우 반전) · false = 오른쪽(기본) const float FacingEps = 0.05f; @@ -88,7 +89,8 @@ namespace TKS string cur = anim.Current ?? ""; string suffix = cur.StartsWith("back_") ? cur.Substring(5) : (cur.StartsWith("front_") ? cur.Substring(6) : "idle"); anim.SetIdle(ClipName("idle")); - if (suffix == "idle") anim.PlayIdle(); + if (charging) anim.Play(ClipName("action"), true); + else if (suffix == "idle") anim.PlayIdle(); else if (suffix == "ready") anim.Play(ClipName("ready"), true); else if (suffix == "victory") anim.Play(ClipName("victory"), false); else anim.Play(ClipName(suffix), false, AttackHold, true); @@ -200,19 +202,34 @@ namespace TKS if (highlightRing != null) highlightRing.enabled = on; } - /// 조준(당기는) 중 = 준비 자세 · 끝나면 대기. + /// 조준(당기는) 중 = 출발 자세(ready · 1프레임) · 끝나면 대기 (PD 2026-11-05 #1084). public void SetAiming(bool on) { if (anim == null || aiming == on) return; aiming = on; if (on) anim.Play(ClipName("ready"), true); - else anim.PlayIdle(); + else if (!charging) anim.PlayIdle(); } - /// 공격 자세(1 프레임) 잠깐 → 대기. + /// 슬링샷 돌진(이동) 중 = 병종 돌진 포즈(action · 1프레임 고정) · 멈추면 대기 (PD 2026-11-05 #1084). + public void SetCharging(bool on) + { + if (anim == null || charging == on) return; + charging = on; + aiming = false; + if (on) anim.Play(ClipName("action"), true); + else if (unit != null && unit.IsAlive) anim.PlayIdle(); + } + + public bool Charging + { + get { return charging; } + } + + /// 공격 자세(1 프레임) 잠깐 → 대기. 돌진 중이면 이미 돌진 포즈라 그대로 둔다. public void PlayAttack() { - if (anim == null || !isActiveAndEnabled) return; + if (anim == null || !isActiveAndEnabled || charging) return; aiming = false; anim.Play(ClipName("action"), false, AttackHold, true); } @@ -237,7 +254,7 @@ namespace TKS if (anim != null) { anim.Renderer.color = ArtHitTint; - if (unit.IsAlive) anim.Play(ClipName("damage"), false, HitHold, true); + if (unit.IsAlive && !charging) anim.Play(ClipName("damage"), false, HitHold, true); // 돌진 중 피격은 색만(포즈 유지) } else { diff --git a/Assets/Tests/PlayMode/BattleFlowTests.cs b/Assets/Tests/PlayMode/BattleFlowTests.cs index ead23498..0f39a260 100644 --- a/Assets/Tests/PlayMode/BattleFlowTests.cs +++ b/Assets/Tests/PlayMode/BattleFlowTests.cs @@ -475,6 +475,21 @@ namespace TKS.Tests rigged.View.PlayAttack(); Assert.AreEqual("back_action", rigged.View.Anim.Current, "공격 자세 클립"); + // PD 2026-11-05 #1084: 조준 중 = 출발 자세(ready) · 돌진 중 = 돌진 포즈(action 고정) · 멈추면 대기 + rigged.View.SetAiming(true); + Assert.AreEqual("back_ready", rigged.View.Anim.Current, "조준(당기는) 중 = 출발 자세"); + rigged.View.SetAiming(false); + rigged.View.SetCharging(true); + Assert.AreEqual("back_action", rigged.View.Anim.Current, "돌진 중 = 병종 돌진 포즈"); + rigged.View.OnHit(); + Assert.AreEqual("back_action", rigged.View.Anim.Current, "돌진 중 피격은 포즈 유지"); + rigged.View.SetCharging(false); + Assert.AreEqual("back_idle", rigged.View.Anim.Current, "멈추면 대기"); + var o2 = new ActionOutcome(); + yield return bm.ResolveForTest(rigged, rigged.Position + new Vector2(0f, 2f), false, o2); + Assert.IsFalse(rigged.View.Charging, "슬링샷이 끝나면 돌진 포즈 해제"); + Assert.AreEqual("back_idle", rigged.View.Anim.Current); + // 원화 세션 1차 납품(2026-11-04): 황건적 5종 정지 그림(front_idle 1장) + 전장 배경 int enemyArt = 0; foreach (var e in bm.AliveUnits(Faction.Enemy))