Hello friends! I'm attempting to implement replay functionality in PICO-8. (e.g. re-watching your last race in a racing game) I started by changing my update function, so that instead of invoking game actions directly, they are added to a command queue. Imagine something like this:
function move_player(x, y) -- move ZIG for great justice end function update_game() if btnp(➡️) then add_cmd(move_player, {1, 0}) end -- other input handling here process_commands() end |
An entry in the queue is a function, parameters (passed as a table), and the frame that the command was added (e.g. 23). At the end of the update function I execute everything in the queue that is scheduled for the current frame. process_commands
uses an index to track where the next command is, and increments the index whenever it executes one. To replay a game, all I have to do is reset my game state and command queue the index to 1, and run my game engine against the already-populated command queue. So far so good, easy enough to implement and it's working fine.
The next thing I thought was how I could use this to run a demo mode for the game. I play the game, I somehow persist the command queue, and use it to drive the demo mode. So now I need to persist this command queue outside of the Lua runtime. My first thought was looking into serialization of data in Lua, but if I understand Lua correctly I'd be serializing the same functions over and over, and it looks like I don't have access to string.dump anyways.
My best idea now is creating a table that keys the string value of my function names on the various game action functions, and add some code to add_cmd
to actually build a string of Lua code that will re-create my table. Seems kinda derpy but it would work, and does require me to change the name table if I change or add game actions.
Another alternative would be to record the raw input data for every frame and re-write my input handling code so that exactly where the input data is coming from is abstracted. Then my data is just a bunch of booleans that are easily serializable, but I hate this because now I'm tracking way more data than I care about, and it makes handling actual user input while the replay is running less straightforward.
How would you approach implementing replay functionality in PICO-8?
I'm a lifelong programmer but very new to game development, feel free to criticize / correct as you see fit, you won't hurt my feelings! I love learning.