303 lines
21 KiB
C#
303 lines
21 KiB
C#
// WL921_Probe.cs — PD 지시 #921 시험(Play 중 · 섬)
|
|
// Rain(seconds, moveAt, moveSec) : 활 각성(화살 비) 발동 — 화살 비 투사체 켜짐 = 0 · 빔(beam_flash · beam_electric) · 낙하 충격(hit_controller 의 area · wave · glow) 보인 처음/끝 · 판정 시각 ·
|
|
// 시전 위치 근처(1.5 m) 이펙트 오브젝트가 사라진 시각과 그 직전 입자 수 · moveAt 초부터 moveSec 초 동안 이동 입력(0 = 이동 없음)
|
|
// Mark(seconds) : 활 주력(속사) 발동 — 과녁(Effect_BulletTarget) 위치와 몸 중심(그림 bounds) 높이 차 · 공중 몹 확인
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
public static class WL921_Probe
|
|
{
|
|
const string Key = "wl921log";
|
|
static StringBuilder Buf()
|
|
{
|
|
var sb = System.AppDomain.CurrentDomain.GetData(Key) as StringBuilder;
|
|
if (sb == null) { sb = new StringBuilder(); System.AppDomain.CurrentDomain.SetData(Key, sb); }
|
|
return sb;
|
|
}
|
|
public static object Log() { return Buf().ToString(); }
|
|
|
|
static float s_t0 = -1f; static readonly StringBuilder s_hits = new StringBuilder(); static int s_n; static ProjectileData s_myPd;
|
|
static void OnHit(in WL.Combat.Core.HitConfirmedEvent e)
|
|
{
|
|
var pd = e.projectile; if (pd == null || pd.m_SkillListTableData == null || pd.m_SkillListTableData.e_Skill.ToString() != "Skill_ArrowRain") return;
|
|
if (s_myPd == null || !ReferenceEquals(pd, s_myPd)) return; // 이번에 쓴 화살 비만
|
|
s_n++; s_hits.Append(s_t0 >= 0f ? (Time.time - s_t0).ToString("F2") : "?").Append(' ');
|
|
}
|
|
|
|
static int Count(Transform root, string child)
|
|
{
|
|
if (root == null) return 0; int n = 0;
|
|
foreach (var ps in root.GetComponentsInChildren<ParticleSystem>(false)) if (ps.name == child) n += ps.particleCount;
|
|
return n;
|
|
}
|
|
|
|
public static object Rain(float seconds, float moveAt, float moveSec)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; s_hits.Length = 0; s_n = 0; s_t0 = -1f; s_myPd = null;
|
|
WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit); WL.Combat.Core.CombatEvents.HitConfirmed.Add(OnHit);
|
|
float tc = Time.time; Vector3 castPos = pc.Get_position(); var fwd = pc.transform.forward; fwd.y = 0f; fwd.Normalize();
|
|
var mdir = Quaternion.Euler(0f, 90f, 0f) * fwd; bool moving = false, moved = false;
|
|
var first = new Dictionary<string, float>(); var last = new Dictionary<string, float>();
|
|
var near = new Dictionary<GameObject, int>(); // 시전 위치 근처 이펙트 → 직전 입자 수
|
|
var old = new HashSet<int>(); foreach (var s in Object.FindObjectsByType<Skill_ArrowRain>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (s != null) old.Add(s.GetInstanceID()); // 자동 전투가 먼저 쓴 화살 비 제외
|
|
var oldFx = new HashSet<int>(); foreach (var ps in Object.FindObjectsByType<ParticleSystem>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (ps != null && ps.transform.parent == null) oldFx.Add(ps.gameObject.GetInstanceID());
|
|
GameObject myRain = null; Skill_ArrowRain mySkill = null; var names = new Dictionary<GameObject, string>();
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float now = Time.time, tcast = now - tc;
|
|
if (moveSec > 0f && !moved && tcast >= moveAt)
|
|
{
|
|
if (!moving) { pc.Set_AutoBraking(false); pc.Set_JoystickStatus(1); moving = true; sb.AppendFormat("{0:F2} ▶ 이동 시작(발동 기준)", tcast).Append('\n'); }
|
|
pc.Run_byJoystick(mdir);
|
|
if (tcast >= moveAt + moveSec) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); moving = false; moved = true; sb.AppendFormat("{0:F2} ■ 이동 끝 · PC 이동 {1:F2} m", tcast, Vector3.Distance(pc.Get_position(), castPos)).Append('\n'); }
|
|
}
|
|
if (s_t0 < 0f) foreach (var s in Object.FindObjectsByType<Skill_ArrowRain>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (s != null && !old.Contains(s.GetInstanceID())) { s_t0 = now; mySkill = s; s_myPd = s.Get_ProjectTileData(); sb.AppendFormat("발동 뒤 {0:F2} 초에 화살 비 켜짐(=0) · 상태 {1}", tcast, pc.Get_CurAnim()).Append('\n'); break; }
|
|
float t = s_t0 >= 0f ? now - s_t0 : -1f;
|
|
if (t >= 0f)
|
|
{
|
|
if (myRain == null) foreach (var ps in Object.FindObjectsByType<ParticleSystem>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (ps != null && ps.transform.parent == null && ps.name == "WL_Fx_BowRain(Clone)" && !oldFx.Contains(ps.gameObject.GetInstanceID())) { myRain = ps.gameObject; break; }
|
|
var rain = myRain;
|
|
if (rain != null)
|
|
foreach (var nm in new[] { "beam_flash", "beam_electric", "area", "wave", "glow" })
|
|
{
|
|
if (Count(rain.transform, nm) <= 0) continue;
|
|
if (!first.ContainsKey(nm)) first[nm] = t; last[nm] = t;
|
|
}
|
|
bool alive = mySkill != null && mySkill.isActiveAndEnabled;
|
|
if (!alive && !first.ContainsKey("~화살비꺼짐")) { first["~화살비꺼짐"] = t; sb.AppendFormat("{0:F2} 화살 비 투사체 꺼짐", t).Append('\n'); }
|
|
}
|
|
// 시전 위치 근처(1.5 m) 이펙트 — 사라지는 순간 기록
|
|
foreach (var ps in Object.FindObjectsByType<ParticleSystem>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|
{
|
|
if (ps == null || ps.transform.parent != null || oldFx.Contains(ps.gameObject.GetInstanceID())) continue; // 루트만 · 시작 전부터 있던 것 제외
|
|
var p = ps.transform.position - castPos; p.y = 0f; if (p.magnitude > 4f) continue;
|
|
if (ps.transform.IsChildOf(pc.transform)) continue;
|
|
int n = 0; byte amax = 0;
|
|
foreach (var c in ps.GetComponentsInChildren<ParticleSystem>(false))
|
|
{
|
|
int k = c.particleCount; n += k; if (k == 0) continue;
|
|
var buf = new ParticleSystem.Particle[k]; k = c.GetParticles(buf);
|
|
for (int i = 0; i < k; i++) if (buf[i].startColor.a > amax) amax = buf[i].startColor.a;
|
|
}
|
|
if (!near.ContainsKey(ps.gameObject)) sb.AppendFormat("{0:F2} 시전 위치 이펙트 생김 {1}", tcast, ps.name).Append('\n');
|
|
near[ps.gameObject] = n * 1000 + amax; names[ps.gameObject] = ps.name;
|
|
}
|
|
var gone = new List<GameObject>();
|
|
foreach (var kv in near) if (kv.Key == null || !kv.Key.activeInHierarchy) gone.Add(kv.Key);
|
|
foreach (var g in gone) { string gn; names.TryGetValue(g, out gn); sb.AppendFormat("{0:F2} 시전 위치 이펙트 사라짐 {3} · 직전 입자 {1} · 최대 알파 {2}/255", tcast, near[g] / 1000, near[g] % 1000, gn).Append('\n'); near.Remove(g); }
|
|
if (tcast > seconds)
|
|
{
|
|
Application.onBeforeRender -= act; WL.Combat.Core.CombatEvents.HitConfirmed.Remove(OnHit);
|
|
if (moving) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); }
|
|
foreach (var kv in first) if (!kv.Key.StartsWith("~")) sb.AppendFormat(" {0} 보임 {1:F2} ~ {2:F2}", kv.Key, kv.Value, last[kv.Key]).Append('\n');
|
|
sb.Append("판정 ").Append(s_n).Append("회 · 시각 ").Append(s_hits).Append('\n');
|
|
}
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "E: " + WL.Combat.Weapon.WLSkillHotkey.Fire(2);
|
|
}
|
|
|
|
/// <summary>애니메이터 상태 state 를 정규화 시각들(n)에 멈춰 PC 옆에서 찍는다 — outPrefix_n.png · 마지막에 대기로 되돌림. 클립 길이 · 이벤트도 적는다.</summary>
|
|
public static object Pose(string state, string nCsv, string outPrefix, float side)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var an = pc.m_animation; var sb = new StringBuilder();
|
|
var ci = System.Globalization.CultureInfo.InvariantCulture;
|
|
var go = new GameObject("~WL921_Pose"); var cam = go.AddComponent<Camera>(); cam.enabled = false; cam.fieldOfView = 35f;
|
|
cam.clearFlags = CameraClearFlags.SolidColor; cam.backgroundColor = new Color(0.1f, 0.12f, 0.16f, 1f);
|
|
var right = pc.transform.right; var center = pc.Get_position() + Vector3.up * 0.7f;
|
|
go.transform.position = center + right * side + Vector3.up * 0.4f + pc.transform.forward * 0.3f; go.transform.LookAt(center + pc.transform.forward * 0.3f);
|
|
float prevSpeed = an.speed; an.fireEvents = false;
|
|
foreach (var s in nCsv.Split(','))
|
|
{
|
|
float n = float.Parse(s, ci);
|
|
an.Play(state, 0, n); an.speed = 0f; an.Update(0f);
|
|
var rt = new RenderTexture(600, 600, 24); cam.targetTexture = rt; cam.Render();
|
|
var prev = RenderTexture.active; RenderTexture.active = rt; var tex = new Texture2D(600, 600, TextureFormat.RGB24, false); tex.ReadPixels(new Rect(0, 0, 600, 600), 0, 0); tex.Apply(); RenderTexture.active = prev;
|
|
System.IO.File.WriteAllBytes(outPrefix + "_" + s + ".png", tex.EncodeToPNG()); Object.Destroy(tex); cam.targetTexture = null; Object.Destroy(rt);
|
|
}
|
|
Object.Destroy(go); an.speed = prevSpeed <= 0f ? 1f : prevSpeed; an.fireEvents = true; pc.Play_Idle();
|
|
foreach (var clip in an.runtimeAnimatorController.animationClips)
|
|
{
|
|
if (clip == null) continue;
|
|
var info = an.GetCurrentAnimatorClipInfo(0);
|
|
if (clip.name == state || (sb.Length == 0 && false)) { }
|
|
}
|
|
return "찍음 " + state;
|
|
}
|
|
|
|
/// <summary>클립 이름들의 길이 · 이벤트(이름@시각).</summary>
|
|
public static object Clips(string namesCsv)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = new StringBuilder(); var want = new HashSet<string>(namesCsv.Split(','));
|
|
foreach (var clip in pc.m_animation.runtimeAnimatorController.animationClips)
|
|
{
|
|
if (clip == null || !want.Contains(clip.name)) continue; want.Remove(clip.name);
|
|
sb.Append(clip.name).Append(' ').Append(clip.length.ToString("F2")).Append("s");
|
|
foreach (var ev in clip.events) sb.Append(" · ").Append(ev.functionName).Append('@').Append((ev.time / Mathf.Max(0.01f, clip.length)).ToString("F2"));
|
|
sb.Append('\n');
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>시험용 — 원본 자동 스킬(PCActor.Update 자동 시전)을 막는다: 칸별 쿨타임 · 자동 간격을 999 초로(핫키 Fire 는 쿨 무시).</summary>
|
|
public static object NoAuto()
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public;
|
|
int n = 0; var sb = new StringBuilder();
|
|
for (var t = pc.GetType(); t != null; t = t.BaseType)
|
|
{
|
|
var f = t.GetField("arr_magicCoolTime", bf);
|
|
if (f != null)
|
|
{
|
|
var arr = f.GetValue(pc) as System.Array;
|
|
if (arr != null) { var et = arr.GetType().GetElementType(); object v = et == typeof(float) ? (object)999f : et.GetMethod("op_Implicit", new[] { typeof(float) }).Invoke(null, new object[] { 999f }); for (int i = 0; i < arr.Length; i++) { arr.SetValue(v, i); n++; } }
|
|
}
|
|
var g = t.GetField("t_autoskill", bf);
|
|
if (g != null) { object v = g.FieldType == typeof(float) ? (object)999f : g.FieldType.GetMethod("op_Implicit", new[] { typeof(float) }).Invoke(null, new object[] { 999f }); g.SetValue(pc, v); sb.Append(" · 자동 간격 999"); }
|
|
}
|
|
return "자동 스킬 막음 칸 " + n + sb;
|
|
}
|
|
|
|
/// <summary>검 각성 동작 사슬 — 프레임마다 상태 이름 일치(namesCsv) · 정규화 시각 · 전이 중 · CurAnim.</summary>
|
|
public static object Chain(string namesCsv, float seconds, int slot)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; var names = namesCsv.Split(','); float t0 = Time.time; string last = "";
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - t0; var an = pc.m_animation; var si = an.GetCurrentAnimatorStateInfo(0); string nm = "?";
|
|
foreach (var n in names) if (si.IsName(n)) { nm = n; break; }
|
|
string key = nm + " " + pc.Get_CurAnim() + (an.IsInTransition(0) ? " 전이" : "");
|
|
sb.AppendFormat("{0:F2} {1} n={2:F2}", t, key, si.normalizedTime).Append(key != last ? " ◀" : "").Append('\n'); last = key;
|
|
if (t > seconds) Application.onBeforeRender -= act;
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "slot" + slot + ": " + WL.Combat.Weapon.WLSkillHotkey.Fire(slot);
|
|
}
|
|
|
|
/// <summary>검 각성 발동 → 마무리 타격(WLSlashFlurry.FinisherHits 증가) 뒤 delay 초에 일시 정지 · chargeAt > 0 이면 마무리 시작 뒤 chargeAt 초(모으기 중)에 멈춘다.</summary>
|
|
public static object PauseFinisher(float delay, float chargeAt, float maxSeconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; int h0 = WL.Combat.Weapon.WLSlashFlurry.FinisherHits, f0 = WL.Combat.Weapon.WLSlashFlurry.Finishers; float at = -1f;
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - t0;
|
|
if (at < 0f)
|
|
{
|
|
if (chargeAt > 0f && WL.Combat.Weapon.WLSlashFlurry.Finishers > f0) at = Time.time + chargeAt;
|
|
else if (chargeAt <= 0f && WL.Combat.Weapon.WLSlashFlurry.FinisherHits > h0) at = Time.time + delay;
|
|
}
|
|
if ((at > 0f && Time.time >= at) || t > maxSeconds)
|
|
{
|
|
Application.onBeforeRender -= act;
|
|
if (at > 0f) UnityEditor.EditorApplication.isPaused = true;
|
|
var cam = Camera.main; var v = cam != null ? cam.WorldToViewportPoint(pc.Get_Center_position()) : Vector3.zero;
|
|
sb.AppendFormat("{0} · t {1:F2} · PC 화면 {2:F3},{3:F3}", at > 0f ? "■ 일시 정지" : "못 찾음", t, v.x, 1f - v.y).Append('\n');
|
|
}
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "slot2: " + WL.Combat.Weapon.WLSkillHotkey.Fire(2);
|
|
}
|
|
|
|
/// <summary>활 기본 화살 직선성 — seconds 동안 Projectile_1040x 마다 프레임 간 진행 방향 꺾임 최대(°) · 비행 프레임 · 사라질 때 몸 중심까지 거리 · 겉모습(기본/3타).</summary>
|
|
public static object Straight(float seconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time;
|
|
var last = new Dictionary<ProjectileBase, Vector3>(); var dir = new Dictionary<ProjectileBase, Vector3>(); var turn = new Dictionary<ProjectileBase, float>(); var frames = new Dictionary<ProjectileBase, int>(); var kind = new Dictionary<ProjectileBase, string>();
|
|
int a0 = WL.Combat.Impact.WLImpactFx.Aims, ar0 = WL.Combat.Impact.WLImpactFx.Arrivals;
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - t0; var d = WL.IslandMob.WLTrailTest.Dummy;
|
|
foreach (var pb in Object.FindObjectsByType<ProjectileBase>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|
{
|
|
if (pb == null || !pb.name.StartsWith("Projectile_1040")) continue;
|
|
var p = pb.transform.position; Vector3 lp;
|
|
if (last.TryGetValue(pb, out lp))
|
|
{
|
|
var mv = p - lp;
|
|
if (mv.sqrMagnitude > 1e-6f)
|
|
{
|
|
Vector3 pd; if (dir.TryGetValue(pb, out pd)) { float a = Vector3.Angle(pd, mv); float m; turn.TryGetValue(pb, out m); if (a > m) turn[pb] = a; }
|
|
dir[pb] = mv; int f; frames.TryGetValue(pb, out f); frames[pb] = f + 1;
|
|
}
|
|
}
|
|
else { var ch = pb.transform.Find("~WL_Charged"); kind[pb] = ch != null && ch.gameObject.activeSelf ? "3타" : "1·2타"; }
|
|
last[pb] = p;
|
|
}
|
|
var gone = new List<ProjectileBase>();
|
|
foreach (var kv in last) if (kv.Key == null || !kv.Key.gameObject.activeInHierarchy) gone.Add(kv.Key);
|
|
foreach (var g in gone)
|
|
{
|
|
float m; turn.TryGetValue(g, out m); int f; frames.TryGetValue(g, out f); string k; kind.TryGetValue(g, out k);
|
|
sb.AppendFormat("{0:F2} 화살({1}) 사라짐 · 비행 {2} 프레임 · 꺾임 최대 {3:F1}° · 몸 중심까지 {4}", t, k, f, m, d != null ? Vector3.Distance(last[g], WL.Combat.Impact.WLImpactFx.BodyCenter(d)).ToString("F2") : "-").Append('\n');
|
|
last.Remove(g); dir.Remove(g); turn.Remove(g); frames.Remove(g); kind.Remove(g);
|
|
}
|
|
if (t > seconds) { Application.onBeforeRender -= act; sb.AppendFormat("끝 · 몸 중심 겨눔 +{0} · 몸 중심 도착 +{1} · {2}", WL.Combat.Impact.WLImpactFx.Aims - a0, WL.Combat.Impact.WLImpactFx.Arrivals - ar0, WL.Combat.Impact.WLImpactFx.LastLog).Append('\n'); }
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "직선성 관찰 " + seconds + " 초";
|
|
}
|
|
|
|
/// <summary>속사(레이저) — 발동 뒤 seconds 동안 속사 화살마다 PC 에서 가장 멀리 간 거리(수평) · 레이저 수 · 맞은 수 · 사정거리.</summary>
|
|
public static object Laser(float seconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; var start = pc.Get_position();
|
|
var far = new Dictionary<ProjectileBase, float>(); var seen0 = new HashSet<int>();
|
|
foreach (var pb in Object.FindObjectsByType<ProjectileBase>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (pb != null) seen0.Add(pb.GetInstanceID());
|
|
int l0 = WL.Combat.Weapon.WLRapidShot.Lasers, h0 = WL.Combat.Weapon.WLRapidShot.LaserHits; float range = WL.Combat.RangeRing.WLRangeRing.AttackReach(pc);
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - t0;
|
|
foreach (var pb in Object.FindObjectsByType<ProjectileBase>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
|
{
|
|
if (pb == null || !pb.name.StartsWith("Projectile_ArcherSkill2Arrow") || seen0.Contains(pb.GetInstanceID())) continue;
|
|
var v = pb.transform.position - pc.Get_position(); v.y = 0f; float m; far.TryGetValue(pb, out m); if (v.magnitude > m) far[pb] = v.magnitude;
|
|
}
|
|
if (t > seconds)
|
|
{
|
|
Application.onBeforeRender -= act;
|
|
sb.AppendFormat("사정거리(흰 원) {0:F2} m · 레이저 +{1} · 맞음 +{2} · {3}", range, WL.Combat.Weapon.WLRapidShot.Lasers - l0, WL.Combat.Weapon.WLRapidShot.LaserHits - h0, WL.Combat.Weapon.WLRapidShot.LastLog).Append('\n');
|
|
foreach (var kv in far) sb.AppendFormat(" 속사 화살 최대 거리 {0:F2} m", kv.Value).Append('\n');
|
|
}
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "Q: " + WL.Combat.Weapon.WLSkillHotkey.Fire(1);
|
|
}
|
|
|
|
public static object Mark(float seconds)
|
|
{
|
|
var pc = MyValue.MyPC as PCActor; if (pc == null) return "PC 없음";
|
|
var sb = Buf(); sb.Length = 0; float t0 = Time.time; float worst = 0f; int frames = 0;
|
|
UnityEngine.Events.UnityAction act = null;
|
|
act = () =>
|
|
{
|
|
float t = Time.time - t0; var d = WL.IslandMob.WLTrailTest.Dummy;
|
|
GameObject mk = null; foreach (var o in Object.FindObjectsByType<TurnOff_GO>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) if (o != null && o.name.StartsWith("Effect_BulletTarget")) { mk = o.gameObject; break; }
|
|
if (mk != null && d != null)
|
|
{
|
|
Bounds b = new Bounds(); bool has = false;
|
|
foreach (var r in d.GetComponentsInChildren<Renderer>(false)) { if (!r.enabled || r is ParticleSystemRenderer) continue; if (!has) { b = r.bounds; has = true; } else b.Encapsulate(r.bounds); }
|
|
float dy = mk.transform.position.y - b.center.y; frames++;
|
|
if (Mathf.Abs(dy) > Mathf.Abs(worst)) worst = dy;
|
|
if (frames == 3) sb.AppendFormat("{0:F2} 과녁 y {1:F2} · 몹 그림 {2:F2}~{3:F2}(중심 {4:F2}) · 차 {5:F2} · 발 y {6:F2} · Center_position y {7:F2} · 몸중심(WL) y {8:F2}", t, mk.transform.position.y, b.min.y, b.max.y, b.center.y, dy, d.Get_position().y, d.Get_Center_position().y, WL.Combat.Impact.WLImpactFx.BodyCenter(d).y).Append('\n');
|
|
}
|
|
if (t > seconds) { Application.onBeforeRender -= act; sb.AppendFormat("끝 · 과녁 보인 프레임 {0} · 과녁-그림 중심 높이 차 최대 {1:F2} m", frames, worst).Append('\n'); }
|
|
};
|
|
Application.onBeforeRender += act;
|
|
return "Q: " + WL.Combat.Weapon.WLSkillHotkey.Fire(1);
|
|
}
|
|
}
|