// 2026년 포트폴리오용 재구성 코드. 실제 업무 당시 소스가 아닙니다. // 2026 portfolio reconstruction. Not original production source. using System; using UnityEngine; namespace PortfolioExamples { // A visual snapshot, deliberately independent from the live training state machine. public struct ReplayFrame { public float Time; public Vector3 Position; public Quaternion Rotation; public bool Visible; public int AnimationState; public float AnimationTime; } public static class ReplayTimeline { public static ReplayFrame Sample(ReplayFrame[] frames, float time) { if (frames == null || frames.Length == 0) throw new ArgumentException("No frames."); if (float.IsNaN(time) || float.IsInfinity(time)) throw new ArgumentException("Invalid time."); // This small standalone sample validates each call. A streaming adapter can validate once on import. for (int i = 0; i < frames.Length; i++) { if (float.IsNaN(frames[i].Time) || float.IsInfinity(frames[i].Time)) throw new ArgumentException("Invalid recorded time."); if (i > 0 && frames[i].Time <= frames[i - 1].Time) throw new ArgumentException("Times must increase."); } if (time <= frames[0].Time) return frames[0]; if (time >= frames[frames.Length - 1].Time) return frames[frames.Length - 1]; int lo = 0, hi = frames.Length - 1; while (hi - lo > 1) { int mid = (lo + hi) / 2; if (frames[mid].Time <= time) lo = mid; else hi = mid; } ReplayFrame a = frames[lo], b = frames[hi]; float t = Mathf.InverseLerp(a.Time, b.Time, time); return new ReplayFrame { Time = time, Position = Vector3.Lerp(a.Position, b.Position, t), Rotation = Quaternion.Slerp(a.Rotation, b.Rotation, t), // Discrete values hold until the next recorded timestamp. Visible = a.Visible, AnimationState = a.AnimationState, AnimationTime = a.AnimationState == b.AnimationState ? Mathf.Lerp(a.AnimationTime, b.AnimationTime, t) : a.AnimationTime }; } } }