Motion.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. namespace Terminal.Gui.TextEffects;
  2. public class Coord
  3. {
  4. public int Column { get; set; }
  5. public int Row { get; set; }
  6. public Coord (int column, int row)
  7. {
  8. Column = column;
  9. Row = row;
  10. }
  11. public override string ToString () => $"({Column}, {Row})";
  12. }
  13. public class Waypoint
  14. {
  15. public string WaypointId { get; set; }
  16. public Coord Coord { get; set; }
  17. public List<Coord> BezierControl { get; set; }
  18. public Waypoint (string waypointId, Coord coord, List<Coord> bezierControl = null)
  19. {
  20. WaypointId = waypointId;
  21. Coord = coord;
  22. BezierControl = bezierControl ?? new List<Coord> ();
  23. }
  24. }
  25. public class Segment
  26. {
  27. public Waypoint Start { get; private set; }
  28. public Waypoint End { get; private set; }
  29. public double Distance { get; private set; }
  30. public bool EnterEventTriggered { get; set; }
  31. public bool ExitEventTriggered { get; set; }
  32. public Segment (Waypoint start, Waypoint end)
  33. {
  34. Start = start;
  35. End = end;
  36. Distance = CalculateDistance (start, end);
  37. }
  38. private double CalculateDistance (Waypoint start, Waypoint end)
  39. {
  40. // Add bezier control point distance calculation if needed
  41. return Math.Sqrt (Math.Pow (end.Coord.Column - start.Coord.Column, 2) + Math.Pow (end.Coord.Row - start.Coord.Row, 2));
  42. }
  43. public Coord GetCoordOnSegment (double distanceFactor)
  44. {
  45. int column = (int)(Start.Coord.Column + (End.Coord.Column - Start.Coord.Column) * distanceFactor);
  46. int row = (int)(Start.Coord.Row + (End.Coord.Row - Start.Coord.Row) * distanceFactor);
  47. return new Coord (column, row);
  48. }
  49. }
  50. public class Path
  51. {
  52. public string PathId { get; private set; }
  53. public double Speed { get; set; }
  54. public Func<double, double> EaseFunction { get; set; }
  55. public int Layer { get; set; }
  56. public int HoldTime { get; set; }
  57. public bool Loop { get; set; }
  58. public List<Segment> Segments { get; private set; } = new List<Segment> ();
  59. public int CurrentStep { get; set; }
  60. public double TotalDistance { get; set; }
  61. public double LastDistanceReached { get; set; }
  62. public Path (string pathId, double speed, Func<double, double> easeFunction = null, int layer = 0, int holdTime = 0, bool loop = false)
  63. {
  64. PathId = pathId;
  65. Speed = speed;
  66. EaseFunction = easeFunction;
  67. Layer = layer;
  68. HoldTime = holdTime;
  69. Loop = loop;
  70. }
  71. public void AddWaypoint (Waypoint waypoint)
  72. {
  73. if (Segments.Count > 0)
  74. {
  75. var lastSegment = Segments.Last ();
  76. var newSegment = new Segment (lastSegment.End, waypoint);
  77. Segments.Add (newSegment);
  78. TotalDistance += newSegment.Distance;
  79. }
  80. else
  81. {
  82. var originWaypoint = new Waypoint ("origin", new Coord (0, 0)); // Assuming the path starts at origin
  83. var initialSegment = new Segment (originWaypoint, waypoint);
  84. Segments.Add (initialSegment);
  85. TotalDistance = initialSegment.Distance;
  86. }
  87. }
  88. public Coord Step ()
  89. {
  90. if (EaseFunction != null && CurrentStep <= TotalDistance)
  91. {
  92. double progress = EaseFunction ((double)CurrentStep / TotalDistance);
  93. double distanceTravelled = TotalDistance * progress;
  94. LastDistanceReached = distanceTravelled;
  95. foreach (var segment in Segments)
  96. {
  97. if (distanceTravelled <= segment.Distance)
  98. {
  99. double segmentProgress = distanceTravelled / segment.Distance;
  100. return segment.GetCoordOnSegment (segmentProgress);
  101. }
  102. distanceTravelled -= segment.Distance;
  103. }
  104. }
  105. return Segments.Last ().End.Coord; // Return the end of the last segment if out of bounds
  106. }
  107. }
  108. public class Motion
  109. {
  110. public Dictionary<string, Path> Paths { get; private set; } = new Dictionary<string, Path> ();
  111. public Path ActivePath { get; private set; }
  112. public Coord CurrentCoord { get; set; }
  113. public Coord PreviousCoord { get; set; }
  114. public EffectCharacter Character { get; private set; } // Assuming EffectCharacter is similar to base_character.EffectCharacter
  115. public Motion (EffectCharacter character)
  116. {
  117. Character = character;
  118. CurrentCoord = new Coord (character.InputCoord.Column, character.InputCoord.Row); // Assuming similar properties
  119. PreviousCoord = new Coord (-1, -1);
  120. }
  121. public void SetCoordinate (Coord coord)
  122. {
  123. CurrentCoord = coord;
  124. }
  125. public Path CreatePath (string pathId, double speed, Func<double, double> easeFunction = null, int layer = 0, int holdTime = 0, bool loop = false)
  126. {
  127. if (Paths.ContainsKey (pathId))
  128. throw new ArgumentException ($"A path with ID {pathId} already exists.");
  129. var path = new Path (pathId, speed, easeFunction, layer, holdTime, loop);
  130. Paths [pathId] = path;
  131. return path;
  132. }
  133. public Path QueryPath (string pathId)
  134. {
  135. if (!Paths.TryGetValue (pathId, out var path))
  136. throw new KeyNotFoundException ($"No path found with ID {pathId}.");
  137. return path;
  138. }
  139. public bool MovementIsComplete ()
  140. {
  141. return ActivePath == null || ActivePath.CurrentStep >= ActivePath.TotalDistance;
  142. }
  143. public void ActivatePath (Path path)
  144. {
  145. if (path == null)
  146. throw new ArgumentNullException (nameof (path), "Path cannot be null when activating.");
  147. ActivePath = path;
  148. ActivePath.CurrentStep = 0; // Reset the path's progress
  149. }
  150. public void DeactivatePath ()
  151. {
  152. ActivePath = null;
  153. }
  154. public void Move ()
  155. {
  156. if (ActivePath != null)
  157. {
  158. PreviousCoord = CurrentCoord;
  159. CurrentCoord = ActivePath.Step ();
  160. ActivePath.CurrentStep++;
  161. if (ActivePath.CurrentStep >= ActivePath.TotalDistance)
  162. {
  163. if (ActivePath.Loop)
  164. ActivePath.CurrentStep = 0; // Reset the path for looping
  165. else
  166. DeactivatePath (); // Deactivate the path if it is not set to loop
  167. }
  168. }
  169. }
  170. public void ChainPaths (IEnumerable<Path> paths, bool loop = false)
  171. {
  172. var pathList = paths.ToList ();
  173. for (int i = 0; i < pathList.Count; i++)
  174. {
  175. var currentPath = pathList [i];
  176. var nextPath = i + 1 < pathList.Count ? pathList [i + 1] : pathList.FirstOrDefault ();
  177. // Here we could define an event system to trigger path activation when another completes
  178. // For example, you could listen for a "path complete" event and then activate the next path
  179. if (loop && nextPath != null)
  180. {
  181. // Implementation depends on your event system
  182. }
  183. }
  184. }
  185. }