• Register
Post news RSS Implementing Time Rewind - And Tearing It Out

Find out how I implemented time rewind in my game, and why I chose to let it go.

Posted by on

In 2012 I was shocked and awed by Portal and Braid, so I decided to make a game about time and space manipulation. If you take two awesome and multiply them together, you get awesome squared, right? Well, no, but that was my understanding of game design at that time. :)


Anyway, I set out to implement rewinding time the naive way, simply saving the position and velocity of every entity into a stack on each frame, in update(). Time rewind is simply popping the state off of the stack during every frame when the time rewind button is pressed, that’s your downdate().

This was fine for a couple of entities, but as levels got larger, surprise surprise, I started to run out of memory. :) Ring buffers to the rescue!

Screen Shot 2019 06 27 at 17 06

With ring buffers, you limit your memory usage by allocating an array of fixed size (N = 16 in this case). You keep a pointer to your current position (head), that’s where you keep your current state. In each update(), you put the stuff in, and increment head (modulo N, to avoid falling off the right edge of the array). In downdate() you just remove the stuff in head, and decrement head (modulo N, to avoid falling off the left edge this time). This works very well if you only need to keep the last N / FPS seconds of gameplay.

Yet, I wanted more. I wanted everything. Just like Jon Blow. He’s a genius. I wanted to be like Jon Blow. So, even more ring buffers to the rescue! :)

Screen Shot 2019 06 27 at 17 06 1

I created multiple ring buffers, each with different speeds. The first one was just like the previous example, the next one had the same size, but only updated on every other frame (keeping state at 2x speed), then the next one updated every fourth frame (4x speed), etc. Being faster, the buffers down the line keep more and more time. The last buffer keeps the last twenty minutes at 256x speed.

During downdate(), I just eat up the first buffer resulting in smooth 1x rewind. When it’s all empty, I switch down to the next buffer, which results in smooth 2x rewind. And so forth all the way down! The more you rewind, the faster it goes, which results in pretty nice user experience, since players don’t want to wait too long when rewinding a lot. Jon Blow had to implement (and explain) a whole speed-tweaking mechanism in Braid which turned out relatively great because he is Jon Blow, and by universal consensus, he is a genius, however, it’s still an additional complication that clunked up his UX.

So. If I aspire to asymptotically approach Jon Blow’s genius, how come I tore out my ingeniously engineered rewind mechanism from my game, just now, two months before the launch?

The short answer is that the main reason for implementing it was to make me feel smart. It didn’t contribute a single puzzle mechanic to the game. Since Terraforming Earth is a rogue-lite puzzle platformer, time rewind even actively detracted from the player experience by incentivizing sloppy gameplay: “*BOOM* lol, nvm, watch this *BBZZZ*” can be fun, but not in a game with perma-death.

Admitting that your pet feature is only there to feed your ego is hard. However, Sid Meier says there are games where the programmer is having all the fun, games where the computer is having all the fun, and games where the players are having all the fun. And he’s also a genius, so, yeah, don’t keep all the fun to yourself! :)

So, what’s Opi’s new skill to replace time rewind? Well, he’s the get-stuff-done piece, so giving him super-strength fits his character and also enables many opportunities for emergent puzzles.


The level generator knows that Opi can move enemy robots, so it can decide to generate situations like this one. How would you get the gang past the obstacle on the left?

Screen Shot 2019 06 27 at 17 02

Steam Early Access is right around the corner, so if you liked this article, consider giving the page some wishlisting love. You can also sign up for the closed beta on our Discord!

Thanks for reading! Remember to let the players have all the fun! :)

Post a comment
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.