Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
MovementController.Scripted.cs
1using System.Numerics;
4
6
10public sealed partial class MovementController
11{
12 private Action<ScriptedMovement>? _scriptCompleted;
13
25 public MovementController OnBeginning(Action callback)
26 {
27 ArgumentNullException.ThrowIfNull(callback);
28
29 return OnBeginning(_ => callback());
30 }
31
45 public MovementController OnBeginning(
46 Action<ScriptedMovement> callback)
47 {
48 ArgumentNullException.ThrowIfNull(callback);
49
50 if (!IsScripted)
51 {
52 throw new InvalidOperationException(
53 "OnBeginning must be called while a scripted movement is active.");
54 }
55
56 callback(_state.Script);
57
58 return this;
59 }
60
73 public MovementController OnComplete(Action callback)
74 {
75 ArgumentNullException.ThrowIfNull(callback);
76
77 return OnComplete(_ => callback());
78 }
79
94 public MovementController OnComplete(
95 Action<ScriptedMovement> callback)
96 {
97 ArgumentNullException.ThrowIfNull(callback);
98
99 if (!IsScripted)
100 {
101 throw new InvalidOperationException(
102 "OnComplete must be called while a scripted movement is active.");
103 }
104
105 _scriptCompleted += callback;
106
107 return this;
108 }
109
133 public MovementController MoveTo(
134 Vector2 target,
135 float durationSec,
136 Func<float, float>? easing = null,
137 float snapEpsilon = 0.5f)
138 {
139 return StartScript(new ScriptedMovement
140 {
141 Type = MovementScriptType.TweenTo,
142 Origin = _mover.GetPosition(),
143 Target = target,
144 DurationSec = MathF.Max(0f, durationSec),
145 ElapsedSec = 0f,
146 SnapEpsilon = MathF.Max(0f, snapEpsilon),
147 Easing = easing
148 });
149 }
150
171 public MovementController MoveTo(
172 Vector2 target,
173 float seconds,
174 EasingKind easingKind,
175 float snapEpsilon = 0.5f)
176 {
177 var easingFunc = EasingFunctions.From(easingKind);
178
179 return MoveTo(
180 target,
181 seconds,
182 easingFunc,
183 snapEpsilon);
184 }
185
208 public MovementController MoveBy(
209 Vector2 delta,
210 float durationSec,
211 Func<float, float>? easing = null,
212 float snapEpsilon = 0.5f)
213 {
214 var goal = _mover.GetPosition() + delta;
215
216 return MoveTo(
217 goal,
218 durationSec,
219 easing,
220 snapEpsilon);
221 }
222
243 public MovementController MoveBy(
244 Vector2 delta,
245 float durationSec,
246 EasingKind easingKind,
247 float snapEpsilon = 0.5f)
248 {
249 var goal = _mover.GetPosition() + delta;
250
251 return MoveTo(
252 goal,
253 durationSec,
254 easingKind,
255 snapEpsilon);
256 }
257
274 public MovementController MoveBy(
275 Vector2 delta,
276 float speedPerSec,
277 float snapEpsilon = 0.5f)
278 {
279 var goal = _mover.GetPosition() + delta;
280
281 return MoveToward(
282 goal,
283 MathF.Max(0f, speedPerSec),
284 snapEpsilon);
285 }
286
308 public MovementController MoveToward(
309 Vector2 target,
310 float speedPerSec,
311 float snapEpsilon = 0.5f)
312 {
313 return StartScript(new ScriptedMovement
314 {
315 Type = MovementScriptType.Toward,
316 Target = target,
317 SpeedPerSec = MathF.Max(0f, speedPerSec),
318 SnapEpsilon = MathF.Max(0f, snapEpsilon)
319 });
320 }
321
327 public void CancelScript()
328 {
329 if (!IsScripted)
330 {
331 _scriptCompleted = null;
332 return;
333 }
334
335 var script = _state.Script;
336
337 // Clear the old script before invoking external code so that an event
338 // handler can safely begin a new movement.
339 _state.Script = default;
340 _scriptCompleted = null;
341
342 ScriptedMovementStopped?.Invoke(script);
343 }
344
345 private MovementController StartScript(
346 ScriptedMovement script)
347 {
348 // A newly assigned script supersedes any completion callback associated
349 // with the previously active script.
350 _scriptCompleted = null;
351
352 _state.Script = script;
353
354 // Scripted movement overrides integrated movement.
355 _state.Acceleration = Vector2.Zero;
356 _state.Velocity = Vector2.Zero;
357
358 ScriptedMovementStarted?.Invoke(script);
359
360 return this;
361 }
362
363 private bool AdvanceScripted(float dt)
364 {
365 switch (_state.Script.Type)
366 {
367 case MovementScriptType.None:
368 return false;
369
370 case MovementScriptType.TweenTo:
371 return AdvanceTween(dt);
372
373 case MovementScriptType.Toward:
374 return AdvanceToward(dt);
375
376 default:
377 return false;
378 }
379 }
380
381 private bool AdvanceTween(float dt)
382 {
383 if (_state.Script.DurationSec <= 0f)
384 {
385 _mover.SetPosition(_state.Script.Target);
386
387 _state.Acceleration = Vector2.Zero;
388 _state.Velocity = Vector2.Zero;
389
390 Step(0f);
391 CompleteScript();
392
393 return true;
394 }
395
396 _state.Script.ElapsedSec += MathF.Max(0f, dt);
397
398 float t = Math.Clamp(
399 _state.Script.ElapsedSec / _state.Script.DurationSec,
400 0f,
401 1f);
402
403 if (_state.Script.Easing is not null)
404 {
405 t = Math.Clamp(
406 _state.Script.Easing(t),
407 0f,
408 1f);
409 }
410
411 var pos = Vector2.Lerp(
412 _state.Script.Origin,
413 _state.Script.Target,
414 t);
415
416 _mover.SetPosition(pos);
417
418 _state.Acceleration = Vector2.Zero;
419 _state.Velocity = Vector2.Zero;
420
421 Step(0f);
422
423 var snapDistanceSquared =
424 _state.Script.SnapEpsilon *
425 _state.Script.SnapEpsilon;
426
427 bool reachedTarget =
428 Vector2.DistanceSquared(
429 pos,
430 _state.Script.Target) <= snapDistanceSquared;
431
432 if (reachedTarget || t >= 1f)
433 {
434 _mover.SetPosition(_state.Script.Target);
435
436 _state.Acceleration = Vector2.Zero;
437 _state.Velocity = Vector2.Zero;
438
439 Step(0f);
440 CompleteScript();
441 }
442
443 return true;
444 }
445
446 private bool AdvanceToward(float dt)
447 {
448 var current = _mover.GetPosition();
449 var to = _state.Script.Target - current;
450 var distance = to.Length();
451
452 if (distance <= _state.Script.SnapEpsilon ||
453 _state.Script.SpeedPerSec <= 0f ||
454 dt <= 0f)
455 {
456 _mover.SetPosition(_state.Script.Target);
457
458 _state.Velocity = Vector2.Zero;
459 _state.Acceleration = Vector2.Zero;
460
461 Step(0f);
462 CompleteScript();
463
464 return true;
465 }
466
467 var stepLength =
468 _state.Script.SpeedPerSec * dt;
469
470 if (stepLength >= distance)
471 {
472 _mover.SetPosition(_state.Script.Target);
473
474 _state.Velocity = Vector2.Zero;
475 _state.Acceleration = Vector2.Zero;
476
477 Step(0f);
478 CompleteScript();
479
480 return true;
481 }
482
483 var direction = to / distance;
484
485 _state.Acceleration = Vector2.Zero;
486 _state.Velocity =
487 direction *
488 _state.Script.SpeedPerSec;
489
490 Step(dt);
491
492 return true;
493 }
494
495 private void CompleteScript()
496 {
497 var script = _state.Script;
498 var completed = _scriptCompleted;
499
500 // Clear the completed movement before invoking external code.
501 // Event handlers and callbacks may safely begin another movement
502 // without that new movement subsequently being erased.
503 _state.Script = default;
504 _scriptCompleted = null;
505
506 ScriptedMovementStopped?.Invoke(script);
507 completed?.Invoke(script);
508 }
509}
Central controller responsible for managing all movement modes for a single IMovable object....
MovementController OnComplete(Action< ScriptedMovement > callback)
Registers a callback to invoke when the currently active scripted movement completes normally.
MovementController MoveBy(Vector2 delta, float durationSec, EasingKind easingKind, float snapEpsilon=0.5f)
Begins scripted relative motion by a delta over a fixed duration using an easing preset.
MovementController OnComplete(Action callback)
Registers a callback to invoke when the currently active scripted movement completes normally.
bool IsScripted
Indicates whether a scripted movement (tween or MoveToward) is currently active.
MovementController MoveToward(Vector2 target, float speedPerSec, float snapEpsilon=0.5f)
Begins scripted motion toward the specified target position at a constant speed.
Action< ScriptedMovement >? ScriptedMovementStarted
Raised when a scripted movement (tween or MoveToward) begins. Subscribers are notified exactly once p...
MovementController OnBeginning(Action callback)
Invokes a callback for the currently active scripted movement.
MovementController MoveBy(Vector2 delta, float durationSec, Func< float, float >? easing=null, float snapEpsilon=0.5f)
Begins scripted relative motion by a delta over a fixed duration with optional easing....
void CancelScript()
Cancels any active scripted movement and clears the current script state. Raises ScriptedMovementStop...
MovementController OnBeginning(Action< ScriptedMovement > callback)
Invokes a callback for the currently active scripted movement.
Action< ScriptedMovement >? ScriptedMovementStopped
Raised when a scripted movement (tween or MoveToward) completes or is explicitly cancelled....
MovementController MoveTo(Vector2 target, float durationSec, Func< float, float >? easing=null, float snapEpsilon=0.5f)
Begins a scripted tween toward the specified target position over a fixed duration....
MovementController MoveBy(Vector2 delta, float speedPerSec, float snapEpsilon=0.5f)
Begins scripted relative motion by a delta at a constant speed.
MovementController MoveTo(Vector2 target, float seconds, EasingKind easingKind, float snapEpsilon=0.5f)
Begins a scripted tween toward the specified target position over a fixed duration,...
void SetPosition(Vector2 pos)
Set the position in the mover's PositionSpace.
EasingKind
Enumeration of all supported easing functions for animation and movement interpolation....
Definition EasingKind.cs:9
MovementScriptType
Defines the type of scripted movement behavior applied to an object. Movement scripts control how an ...
Represents the state and parameters of a scripted movement operation applied to an object....
float DurationSec
The total duration of the movement in seconds. Only used by MovementScriptType.TweenTo to determine t...
Vector2 Target
The target position or destination for the movement. For MovementScriptType.TweenTo,...
MovementScriptType Type
The type of movement script currently active. Determines which fields are relevant and how the moveme...