GML Time Rewind Feature Tutorial


Tutorial Guy
YYG Staff
GM Version: GMS2, works with GMS1 too
Target Platform: All


A friend of mine was making a game and needed help with implementing a time rewind feature, so I quickly cooked up some code for him. Works like a charm, so I thought I'd share it here.


Basically, we have a DS list that stores the data for each step inside it, which we can use to rewind the time. In this example, the DS list is inside the player object, and stores its x, y and health in an array, then pushes it to the list.

I recommend you do this in a controller object, and store the data of all the instances in the list, for a proper time rewind.

Of course, this code isn't perfect and was written in a couple minutes, so if you wanna improve on it or point out a mistake, I'd appreciate it.

Create event:
td = ds_list_create(); // List that stores data for each step
td_rewind = 0; // How much to rewind

max_seconds = 3; // Max time you can rewind
The td_rewind variable will be used to go back from the last element in the list. So it'll be a negative value, with its minimum value being -list_size.

Step event:
var rewind_key = keyboard_check(ord("R"));

// Basic movement, move only if the rewind key is not pressed
if (!rewind_key) {
   x += keyboard_check(vk_right) - keyboard_check(vk_left);
   y += keyboard_check(vk_down) - keyboard_check(vk_up);

// Add current step's data to the list as an array
if (!rewind_key)  // Not being rewinded
   ds_list_add(td, [x, y, health]); // <- You gotta store as much data as you can, to make the reverse realistic

// Delete first element if it goes past the max time
if (ds_list_size(td) > 60 * max_seconds) { // max_seconds is 3
   ds_list_delete(td, 0);

// Now to rewind
var size = ds_list_size(td);

if (rewind_key && size + td_rewind > 0) { // Second condition makes sure that we don't go past the list size
   td_rewind--; // Go back

   // Reapply data from list
   var arr = td[| size + td_rewind];
   x = arr[0];
   y = arr[1];
   health = arr[2];
// Reset rewind
else if (!rewind_key) {
   td_rewind = 0;
Clean up event:
Hope it helps anyone out there!