Improved Tweening in MonoGame.Extended

Tweening Squares

Have you ever made your game juicy? If so, you’ll know that tweening is at the heart of great juice.

Basic tweening is a pretty simple concept. You’ll find it in just about every game you’ve ever played. Often, you’ll implement it in your game without really thinking about it. Sometimes that’s enough.

On the other hand, as you start polishing your game you’ll find yourself wanting to tween lots of things. You hack it in here and wack it in there. It works, but your code gets pretty messy, pretty quickly.

I found myself in just that situation fairly recently. So I spent a few weeks researching and designing the new Tweener class in MonoGame.Extended. It’s designed to be a nice clean, reusuable way to implement tweens when you need them.

First, create a Tweener. Tweeners hold tweens while they play. You can use it to create new tweens or cancel groups of tweens together after they start playing.

_tweener = new Tweener();

Don’t forget to call the tweeners Update method every frame.

_tweener.Update(elapsedSeconds);

Now we can get to the good stuff. Let’s imagine you have a gameObject of some sort that you want to move from it’s current position to a new position over time.

_tweener.TweenTo(gameObject, a => a.Position, new Vector2(550, 200), duration, delay)
    .Easing(EasingFunctions.BounceOut);

That’s it. You’re gameObject will start moving to it’s new position after the delay and it’ll take duration seconds to get there. To make it really nice, we add an Easing function to make it more juicy and fun.

Once the tween completes it’ll be removed from the tweener automatically. If you need more control you can grab the tween returned from the tweener and hang on to it.

_tween = _tweener.TweenTo(gameObject, a => a.Position, new Vector2(5, 5));
_tween.Pause();

When you’re creating new tweens you can chain together different behaviours. For example, the tweens shown in the above gif play forwards and backwards, then repeat forever.

_tweener.TweenTo(square, a => a.Position, new Vector2(550, 300), duration, delay)
    .RepeatForever(repeatDelay)
    .AutoReverse()
    .Easing(EasingFunctions.ElasticOut);

If we happen to start a new tween on the same property while an existing tween is playing, the existing tween will be cancelled and the new tween will take over.

if (mouseState.WasButtonJustDown(MouseButton.Left))
{
    _tweener.TweenTo(gameObject, a => a.Position, mouseState.Position.ToVector2(), 1.0f)
        .Easing(EasingFunctions.QuadraticOut);
}

This prevents tweens “fighting” each other and causing jarring glitchy movements.

Happy coding!