-
Notifications
You must be signed in to change notification settings - Fork 0
Core.Tween
This part of the engine handles Tweening, which is the process of generating intermediate values between two states (like positions, colors, or scales) over time.
-
The "Normal" (0 to 1): Most functions here depend on a (often called ).
-
0.0means the start of the animation. -
1.0means the end.
-
normal``t
2. Easing ():ApplyEasing Real-world movement isn't usually constant speed. Easing functions take a linear normal and "curve" it (e.g., starting slow and speeding up) to make movement look natural.
3. TweenStacks: These are powerful because they allow you to "stack" multiple animations into one single timeline. For example, you can say: "From 0.0 to 0.5, move from A to B, and from 0.5 to 1.0, move from B to C."
To use these functions, you need a timer that converts real time (seconds/milliseconds) into that 0 to 1 normal. While we will discuss the internals of and later, here is how you combine them with the tween system. FixedTimer``TimerOn
This is the most basic usage. You take two points and a normal from a timer to find the position in between.
// Assuming timer is an instance of FixedTimer or TimerOn
// that has been started with a specific duration.
float normal = timer.NormalizedElapsed;
// Apply easing to make it smooth
float smoothedNormal = Tween.ApplyEasing(normal, EaseType.EaseInOutCubic);
// Move from (0,0) to (100, 100)
Vector2 currentPos = Tween.Lerp(new Vector2(0, 0), new Vector2(100, 100), smoothedNormal);A is useful when you want one timer to trigger a sequence of events. You define the segments once, then just pass the timer's normal to the method. TweenStack``Lerp
// 1. Setup the stack (usually done once at initialization)
var healthBarStack = new TweenStack();
healthBarStack.AssignFromValue(1.0f) // Start at full scale
.Register(EaseType.EaseOutBounce, 0.0f, 0.5f) // Bounce down to 0.5 from 0% to 50% time
.AssignToValue(0.5f)
.Register(EaseType.Linear, 0.5f, 0.5f) // Stay at 0.5 or move to 0.8 from 50% to 100%
.AssignToValue(0.8f);
// 2. In your Update loop
// timer.Normal goes from 0 to 1 over its duration
float currentScale = healthBarStack.Lerp(timer.Normal);If you want to move an object through a path of points using a single timer:
// Define a path: at 0% be at start, at 20% be at point A, at 100% be at target
var moveStack = new TweenStackVector2().FromKeyframes(
(0.0f, new Vector2(0, 0), EaseType.Linear),
(0.2f, new Vector2(10, 50), EaseType.EaseOutQuad),
(1.0f, new Vector2(200, 0), EaseType.EaseInOutSine)
);
// Every frame, just ask the stack where we should be based on the timer
Vector2 position = moveStack.Lerp(timer.Normal);-
ApplyEasing(t, ease): Transforms a "straight line" progress into a "curved" progress. -
Lerp(...): Calculates the value between point A and B based on the progress. -
PingPong(time, period): Useful for repeating animations (like a hovering item) that go back and forth. -
StepTo(...): Unlike Lerp (which is time-based), this is speed-based. It moves a value by a fixed amount every frame.
- Linear: Constant speed from start to finish.
- EaseIn / EaseOut / EaseInOut: Standard quadratic easing (x^2). Provides a smooth, natural acceleration and deceleration.
These follow the same curve logic as standard easing but with increasing intensity:
- Cubic (x^3): Moderately sharp acceleration/deceleration.
- Quart (x^4): Sharp acceleration/deceleration.
- Quint (x^5): Extremely sharp acceleration/deceleration; starts very slow and finishes very fast.
- Sine: A gentle, organic curve based on sine waves. It is the smoothest and least aggressive of all easing functions.
- Back: Includes an "anticipation" or "overshoot" effect where the value briefly goes outside the 0–1 range before settling.
- Bounce: Mimics the movement of a bouncing ball, hitting the target value and recoiling several times.
- Elastic: Mimics a spring or rubber band, with a rapid oscillation (wobble) around the start or end point.
- In: The effect (acceleration, bounce, or overshoot) occurs at the start.
- Out: The effect occurs at the end.
- InOut: The effect is applied symmetrically to both the start and the end.
The MoveToTarget class in the Meatcorps.Engine.Core.Tween namespace is a utility designed to move an object from one 2D point to another at a constant speed over time. It is a simple linear interpolator that calculates the current position based on elapsed time (deltaTime).
-
Initialization (
Startmethod):- It takes a starting point (
from), a target point (to), and a movementspeed. - It calculates the normalized
_directionvector (where to go). - It calculates the initial
DistanceRemainingto know when to stop.
- It takes a starting point (
-
Movement Logic (
Updatemethod):- It calculates how far the object should move this frame:
moveAmount = Speed * deltaTime. -
Overshoot Protection: If the
moveAmountis greater than or equal to theDistanceRemaining, it snaps thePositionexactly to theTargetPositionand setsDonetotrue. This prevents the object from vibrating around the target or flying past it. - Otherwise, it increments the
Positionalong the direction vector and subtracts the moved distance fromDistanceRemaining.
- It calculates how far the object should move this frame:
-
State Tracking:
-
Position: Exposes the current coordinates so you can apply them to your game object. -
Done: A boolean flag you can check to trigger events (like destroying the object or starting a new path) once the destination is reached.
-
Here is an example of how you might use MoveToTarget within a game object or a component:
using System;
using System.Numerics;
using Meatcorps.Engine.Core.Tween;
public class Projectile
{
private MoveToTarget _mover = new MoveToTarget();
public Vector2 CurrentPosition => _mover.Position;
public void Launch(Vector2 start, Vector2 target, float speed)
{
_mover.Start(start, target, speed);
Console.WriteLine($"Projectile launched from {start} towards {target}.");
}
public void Update(float deltaTime)
{
if (!_mover.Done)
{
_mover.Update(deltaTime);
Console.WriteLine($"Moving... Current Position: {_mover.Position}");
if (_mover.Done)
{
OnReachedTarget();
}
}
}
private void OnReachedTarget()
{
Console.WriteLine("Target reached!");
}
}
// Simulating a game loop
/*
var bullet = new Projectile();
bullet.Launch(new Vector2(0, 0), new Vector2(10, 0), 5f); // Move to (10,0) at 5 units/sec
bullet.Update(1.0f); // Moves to (5, 0)
bullet.Update(1.0f); // Moves to (10, 0) and sets Done = true
*/-
Position: The current location of the object. -
Speed: How many units the object moves per second. -
Done: Returnstruewhen theTargetPositionhas been reached. -
DistanceRemaining: Helpful if you want to scale effects (like sound or transparency) based on how close the object is to the target.
ArcMoveToTarget is a specialized movement class designed to move an object from one point to another following a parabolic arc (like a jump or a projectile toss) rather than a straight line.
-
Inheritance: It inherits from
MoveToTarget, which handles the basic linear logic of moving from point A to point B at a constant speed. -
Linear Foundation: Every frame, it first calls
base.Update(deltaTime). This moves the object forward along a straight line toward the target. - Progress Calculation: It calculates how far the object has traveled as a percentage (0.0 to 1.0) by comparing its current distance from the start to the total distance to the target.
-
The Arc Math: It uses the formula
4 * progress * (1 - progress)to calculate a vertical offset.- At 0% progress:
$4 \times 0 \times 1 = 0$ - At 50% progress:
$4 \times 0.5 \times 0.5 = 1$ (The peak of the arc) - At 100% progress:
$4 \times 1 \times 0 = 0$
- At 0% progress:
-
Height Application: This value is multiplied by
ArcHeightand subtracted from the$Y$ coordinate (assuming a coordinate system where smaller$Y$ is "higher" or simply treating it as an offset from the linear path).
Here is how you would use this class to simulate a "toss" effect, for example, an item dropping from a chest or a character jumping.
using System.Numerics;
using Meatcorps.Engine.Core.Tween;
public class ProjectileExample
{
private ArcMoveToTarget _arcMover = new ArcMoveToTarget();
public void TossItem(Vector2 startPos, Vector2 endPos)
{
// 1. Configure the arc
_arcMover.ArcHeight = 50.0f; // The peak will be 50 units high
// 2. Start the movement (from, to, speed)
// This comes from the base MoveToTarget class
_arcMover.Start(startPos, endPos, 200.0f);
}
public void Update(float deltaTime)
{
if (!_arcMover.Done)
{
// 3. Update the logic every frame
_arcMover.Update(deltaTime);
// 4. Use the calculated position to update your sprite/object
Vector2 currentPos = _arcMover.Position;
Console.WriteLine($"Current Position: {currentPos}");
}
else
{
Console.WriteLine("Arrival reached!");
}
}
}-
ArcHeight: Controls how high the "jump" goes. A higher value makes the arc steeper. -
Speed: Controls how fast the object moves horizontally toward the target. -
Done: A boolean flag you can check to see if the movement has finished.
The class is a utility designed to move an object along a sequence of coordinates (waypoints) at a constant speed. It is commonly used in game development or simulations for NPC movement, camera paths, or UI animations. PathMover
-
Path Initialization: When you call , you provide a starting position and a collection of points. These points are stored in a , which ensures they are visited in the order they were provided.
Start``Queue -
Movement Logic: The method is intended to be called every frame (passing in the time elapsed since the last frame, ). It calculates how far the object should move based on its and updates the .
Update``deltaTime``Speed``Position - Waypoint Transition: When the object reaches its current target waypoint, it automatically dequeues the next one.
-
Looping: If is set to , a waypoint is added back to the end of the queue as soon as it is reached, allowing for continuous movement in a cycle.
Loop``true
-
Position: The current coordinate of the mover. -
Speed: How many units the mover travels per second. -
DistanceRemaining: The distance left to reach the current waypoint (not the entire path). -
Done: A flag that becomes once all waypoints have been reached (if is false).true``Loop
Here is an example of how you might use to move a character along a square path. PathMover
using System.Numerics;
using Meatcorps.Engine.Core.Tween;
public class PathExample
{
public void Run()
{
PathMover mover = new PathMover();
// 1. Define the start position and the path (waypoints)
Vector2 startPos = new Vector2(0, 0);
List<Vector2> waypoints = new List<Vector2>
{
new Vector2(10, 0), // Move Right
new Vector2(10, 10), // Move Up
new Vector2(0, 10), // Move Left
new Vector2(0, 0) // Move back to Start
};
// 2. Start the mover (Speed: 5 units per second, Looping: enabled)
mover.Start(startPos, waypoints, speed: 5.0f, loop: true);
// 3. Simulating a game loop
float deltaTime = 0.16f; // Simulating ~60 FPS
for (int i = 0; i < 20; i++)
{
mover.Update(deltaTime);
Console.WriteLine($"Current Position: {mover.Position}, Distance to target: {mover.DistanceRemaining:F2}");
if (mover.Done) break;
}
}
}While is designed for a simple point-A to point-B movement, is more robust because it handles a list of points automatically. Once one point is reached, immediately starts heading toward the next without requiring external logic to trigger the next move. MoveToTarget``PathMover``PathMover