using Cryville.Crtr.Skin.Components; using System.Linq; using UnityEngine; namespace Cryville.Crtr.Event { public abstract class TransformHandler : ContainerHandler { protected abstract TransformHandler Parent { get; } public override void Init() { base.Init(); sgos = Components.OfType().ToArray(); } SectionalGameObject[] sgos; bool sflag; // Did pre-graphical update Vector3 spos; // Start position offset Vector3 ppt = Vector3.zero; // Previous screen point Vector3 plp = Vector3.zero; // Previous local point Vector3 pwp = Vector3.zero; // Previous world point Vector3 ppwp = Vector3.zero; // Previous parent world point double ptime; // Previous time float length; public override void StartPhysicalUpdate(ContainerState s) { base.StartPhysicalUpdate(s); if (CanDoGraphicalUpdate(s)) { TransformAwake(s); } } protected override void StartPreGraphicalUpdate(ContainerState s) { base.StartPreGraphicalUpdate(s); spos = Vector3.zero; sflag = true; pwp = Parent != null ? Parent.Position : Vector3.zero; TransformAwake(s); } protected override void StartGraphicalUpdate(ContainerState s) { base.StartGraphicalUpdate(s); if (RootTransform) { if (!sflag && Parent != null) { // No pre-graphical update; inherit from parent spos = Parent.Position + (Vector3)s.ScreenPoint - (Vector3)s.Parent.ScreenPoint; } TransformAwake(s); var p = Position; foreach (var i in sgos) { i.Reset(); i.AppendPoint(p, Rotation); } } } void TransformAwake(ContainerState s) { plp = s.ScreenPoint; pwp = Vector3.zero; ptime = s.Time; Position = spos; Rotation = s.QuatDir; } public override void Update(ContainerState s, StampedEvent ev) { base.Update(s, ev); if (CanDoGraphicalUpdate(s)) { ppt = s.ScreenPoint; var tsv = s.ScrollVelocity; Vector3 dpt = ppt - plp; // Delta 2D point dpt.z = (float)((s.Time - ptime) * ChartPlayer.sv * tsv); // Delta Z Quaternion rotq = Quaternion.Euler(s.Direction); // Rotation var dwp = rotq * dpt; // Delta world point var nl = length + dwp.magnitude; // New length var tdist = s.Distance; if (nl >= tdist) { // TODO Fix dist s.Break(); return; } length = nl; var wp = pwp + dwp; // World point pwp = wp; if (Parent != null) ppwp = Parent.Position; plp += dpt; ptime = s.Time; Position = pwp + spos; Rotation = s.QuatDir; if (!RootTransform || s.CloneType == 3) return; foreach (var i in sgos) i.AppendPoint(Position, Rotation); } else UpdatePosition(s); } void UpdatePosition(ContainerState s) { plp = s.ScreenPoint; pwp = Vector3.zero; ptime = s.Time; length = 0; Position = pwp + spos; Rotation = s.QuatDir; } // TODO Fix anchor rotation public override void Anchor() { base.Anchor(); spos = ppt - Position; if (ptime < cs.Time) { // Pre-graphical update ends before anchor, compensate from parent var dspos = ppwp - (Parent != null ? Parent.Position : Vector3.zero); spos += dspos; Position -= dspos; } } protected override void EndGraphicalUpdate(ContainerState s) { base.EndGraphicalUpdate(s); EndUpdatePosition(s); var p = Position; foreach (var i in sgos) { i.AppendPoint(p, Rotation); i.Seal(); } sflag = false; } void EndUpdatePosition(ContainerState s) { ppt = s.ScreenPoint; var tsv = s.ScrollVelocity; Vector3 dpt = ppt - plp; dpt.z = (float)((s.Time - ptime) * ChartPlayer.sv * tsv); Quaternion rotq = Quaternion.Euler(s.Direction); var dwp = rotq * dpt; // Delta world point var nl = length + dwp.magnitude; // New length var tdist = s.Distance; if (nl >= tdist) dwp *= (tdist - length) / (nl - length); length = nl; var wp = pwp + dwp; // World point pwp = wp; plp += dpt; Position = pwp + spos; Rotation = s.QuatDir; } } }