Problems using easing equations in C# XNA

I'm having some trouble using the easing equations suggested by Robert Penner for ActionScript (http://www.robertpenner.com/easing/, and a Flash demo here) in my C# XNA game. Firstly, what is the definition of the following variables passed in as arguments to each equation?

float t, float b, float c, float d

I'm currently calculating the new X position of a sprite in the Update() loop, however even for the linear tween equation I'm getting some odd results. I'm using the following values:

float t = gameTime.TotalGameTime.TotalMilliseconds;
float d = 8000f;
float b = x.Position.X;
float c = (ScreenManager.Game.GraphicsDevice.Viewport.Width >> 1) - (x.Position.X + x.frameSize.X / 2);

And this equation for linear easing:

float val = c*t/d + b;
• Apologies, will add - seems pretty much every library uses these! – codinghands Apr 5 '12 at 19:43
• First error... used 'milliseconds' instead of 'TotalMilliseconds' – codinghands Apr 5 '12 at 19:55

Firstly, what is the definition of the following variables passed in as arguments to each equation?

The answer was in the link you provided:

• t = current time (starting from 0 and increasing up to the chosen duration)
• d = duration (i.e. total time of the animation)
• b = initial value
• c = change in value (i.e. how much the value should change, or the difference between the final value and the initial value)

Now for your troubles. Let's take a look at the values you chose for t and d:

float t = gameTime.TotalGameTime.TotalMilliseconds;
float d = 8000f;

I'm guessing you want your interpolation to take 8 seconds to complete, i.e. 8000 miliseconds. In that case the value of t should be starting a 0 on the first frame of the interpolation, and increment a little each frame until it reaches 8000, at which point you should stop updating because the interpolation is complete.

The problem is that you're passing it the value of gameTime.TotalGameTime which is the time that has passed since the game began, and you're supposed to pass it the time that has passed since the animation has begun. Here's the proper solution. First:

// Once at the start of the animation
// Note: I'll also use seconds instead of miliseconds
float t = 0f;
float d = 8f;
bool animating = true;

And then:

// Then once for each frame while the animation is active (i.e. in Update)
if(animating)
{
t += gameTime.ElapsedGameTime.TotalSeconds;

// Don't let time exceed the duration
t = MathHelper.Min(t, d);

// Calculate your "val" here
float val = b + t/d * c;

// Stop animating if we've reached the end
if(t >= d)
animating = false;
}

As for your other values, the value of c looks really cryptic and I'm not really sure what you're trying to do. But basically in this given context, c should be the amount of units you want your character to move.

Finally, unless you're trying to do some really fancy easing, I would just use one of the XNA's built in methods for this:

• Thank you very much David - I'd spotted the definitions in the link but just wanted to be crystal clear I hadn't misunderstood anything (which I obviously had!). This is the critical part I managed to comprehensively misunderstand - which is the time that has passed since the game began, and you're supposed to pass it the time that has passed since the animation has begun. 'c' is just a distance calculation to centre a sprite in the middle of the screen. Where in a game would the 't', 'd', and 'animating' values normally be stored - within the object being animated? – codinghands Apr 5 '12 at 20:23
• Or maybe even storing a list of 'motions' within my 'Sprite' object, then checking these on 'Update'... – codinghands Apr 5 '12 at 20:26
• @codinghands Yes that's a possibility, keeping it inside the object. But a more flexible solution would be to create a separate class, e.g. Animator which would keep these values, and you could use it for instance like: Animator anim = new Animator(character, destination, duration); and call anim.Update(gameTime); each frame. That's mostly a design decision and there are many ways to implement it. – David Gouveia Apr 5 '12 at 20:28
• That's even better. Learning a lot along the way here - many thanks for your help and patience. – codinghands Apr 5 '12 at 20:31

This are the meanings:

t = TimeElapsed => Range[0, Duration]
b = InitialValue;
c = FinalValue - InitialValue;
d = Duration;

I have a similar code to this for every easing function:

public static partial class Tweening {
public static class Quartic {
public static float EaseIn( float t, float b, float c, float d ) {
return c * (t /= d) * t * t * t + b;
}
public static float EaseOut( float t, float b, float c, float d ) {
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
}
public static float EaseInOut( float t, float b, float c, float d ) {
if ( (t /= d / 2) < 1 ) {
return c / 2 * t * t * t * t + b;
}
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
}
}
}

And if you make an Animator class you can use a delegate method like this:

public delegate float TweeningFunction( float timeElapsed,
float start,
float change,
float duration );

This way you can change easily the Animator behaviour changing the ease function...

public Movement {
public TweeningFunction Function;
....
}

MovementInstance.Function = Tweening.Quartic.EaseIn;

In this video I used this approach... you can see it at the code shown at first seconds..