// ───────────────────────────────────────────────────────────────────────────── // WLFlyingHitbox.cs — 떠 있는 몹의 피격 판정을 지면까지 늘린다 (#919 · 2026-10-18) // // PD 원문: 「비행 중인 몬스터도 보이는 것과 별개로 지상에서 공격이 가능하도록 해줘.」 // ■ 실측 — 원본 투사체는 OnTriggerEnter → 맞은 콜라이더의 TryGetComponent 로 맞힌다(= 몹 루트 BoxCollider). // 몹 프리팹 303 개 중 그 판정 상자 바닥이 발 위로 뜬 것 4 개(RPG_Bat 0.21 m · Firetree_A/B/C 0.32 m). // 섬의 박쥐(배율 0.57) 판정 = 지면 위 0.32~1.17 m — 지면 쪽 판정(검 각성 돌진 베기 꼭대기 0.51 m)과 0.19 m 만 겹쳤다. // ■ 방법 — 몹 등장(CombatEvents.Spawned · MobActor.On_Regen 원본 훅) 때 루트 BoxCollider 바닥이 발보다 minGap 넘게 높으면 // 바닥만 발(+ groundPad)까지 내린다(꼭대기 · 가로 · 세로 그대로). 원래 크기를 기억해 다시 등장해도 누적되지 않는다. // 보이는 모습 · 몸 중심(Get_Center_position = 스킨 bounds · WLImpactFx.BodyCenter = 발~머리) · 몸 반지름(가로)은 그대로. // ■ 값 = Resources/WL/WLFlyingHitbox.json (C45) · 끄기 = enabled 0 // 🔴 원본 수정 0줄 · Debug.LogError 금지. // ───────────────────────────────────────────────────────────────────────────── using UnityEngine; using WL.Combat.Core; namespace WL.Combat.Reaction { [System.Serializable] public class WLFlyingHitboxJson { public int enabled = 1; public float minGap = 0.1f; // 판정 바닥이 발보다 이만큼(m) 넘게 높으면 「떠 있음」 public float groundPad; // 늘린 바닥 = 발 + groundPad(m · 음수 = 땅 아래까지) public string note = ""; } /// 늘리기 전 판정 상자(로컬) — 다시 등장할 때 이 값에서 다시 계산한다. public sealed class WLFlyingHitboxBase : MonoBehaviour { public Vector3 center, size; } public static class WLFlyingHitbox { public const string ResourcesPath = "WL/WLFlyingHitbox"; public static int Extended; public static string LastLog = ""; static WLFlyingHitboxJson s_cfg; static WLFlyingHitboxJson Cfg { get { if (s_cfg != null) return s_cfg; s_cfg = new WLFlyingHitboxJson(); var ta = Resources.Load(ResourcesPath); if (ta == null) { LastLog = "설정 없음 " + ResourcesPath; return s_cfg; } try { JsonUtility.FromJsonOverwrite(ta.text, s_cfg); } catch (System.Exception ex) { LastLog = "설정 파싱 실패 — " + ex.Message; } return s_cfg; } } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] static void Register() { s_cfg = null; Extended = 0; CombatEvents.Spawned.Remove(OnSpawned); CombatEvents.Spawned.Add(OnSpawned); } static void OnSpawned(in SpawnedEvent e) { if (e.actor is MobActor) Apply(e.actor); } /// 판정 상자 바닥이 떠 있으면 발까지 내린다 — 늘렸으면 true. public static bool Apply(Actor a) { var c = Cfg; if (c.enabled == 0 || a == null) return false; var box = a.GetComponent(); if (box == null) return false; var bs = a.GetComponent(); if (bs == null) { bs = a.gameObject.AddComponent(); bs.center = box.center; bs.size = box.size; } float sy = Mathf.Abs(a.transform.lossyScale.y); if (sy < 1e-4f) return false; float lo = bs.center.y - bs.size.y * 0.5f, hi = bs.center.y + bs.size.y * 0.5f; // 루트(= 발 · Actor.Get_position) 로컬 if (lo * sy <= c.minGap) { box.center = bs.center; box.size = bs.size; return false; } float newLo = c.groundPad / sy; box.size = new Vector3(bs.size.x, hi - newLo, bs.size.z); box.center = new Vector3(bs.center.x, (hi + newLo) * 0.5f, bs.center.z); Extended++; LastLog = a.name + " 판정 바닥 " + (lo * sy).ToString("F2") + " m → " + c.groundPad.ToString("F2") + " m · 꼭대기 " + (hi * sy).ToString("F2") + " m"; return true; } } }