Log In  

Cart #playback_a-0 | 2022-01-18 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

TO LOAD THIS CART in immediate mode, type load #playback_a

VVhat's new ?
✅ New BTN() can now be called with no arguments, returns numeric of all buttons, thanks to @SmellyFishstiks.
✅ Beefed up the documentation and usage instructions.

This program will let you record and playback keystrokes, including saving your code with those compressed keystrokes in very small code indeed.

First off, the record and playback routine is 436-characters total, so this entire method is pretty small at that. Add about 46-characters for each of the functions record() and play() and you're home free !

Further I did not make this game. It is JELPI, written by @zep, a demo game which is included when you purchase Pico-8.

What I have written are two primary functions. One to record keystrokes as you play the game and transfer them to the clipboard as new source code - and the other is to simply play them back as you have listed.

This replaces the btn() function with my own. Include the 3-functions that + typing at the top of your code: _b0=btn and you are perfectly done. Nothing whatsoever else is needed. See the code below on usage:

function record()
function playback()
function btn(p)local b=_b0()if _bm==1then if b!=_bl then if _bd>""then _bd=_bd.._bt..","else _bd=""_bt=0_bp=1end _bl=b _bd=_bd..b..","_bt=0else _bt+=1end if _b0()==15then printh("btnpb={"..sub(_bd,1,#_bd-1).."}\n","@clip")stop()end return _b0(p)elseif _bm==2then if _bt>0then _bt-=1else _bs=btnpb[_bp]_bt=btnpb[_bp+1]_bp+=2if _bt==nil then _bm=0end end if p==nil then return _bs elseif band(_bs,2^p)>0then return true else return false end else return _b0(p)end end

. . .

(( The beginning of your code, _init() or what have you ))

When you choose RECORD, you can play the game as normal with no changes to your sourcecode. Every keystroke is recorded through a new version of BTN() as you can see. To stop recording at any time by press all 4-arrow keys at the same time, this will also stop the cart and return back to the editor. Then you can choose a line of your source code and press CTRL+V to paste the new button set you just used to play your game. It might appear like this:


Then select PLAYBACK after the btnpb= definition and run your cart again. You will see all of your keystrokes played back exactly as you did them with exact timing and everything. When the end of your keystrokes is reached, game input returns to normal and you can continue playing your game right where it was left off.

There is slight compression in here in that it counts the number of cycles you repeat a keystroke or series of keystrokes. So it doesn't just record 30-numbers for 30-frames of data, that would make the data too big. In fact to play this entire demo game of JELPI above from beginning to end took only 265-numbers or true 687-characters of space.

There are more details and instructions in the cart listed above, examine them for additional assistance.

And that's it ! Choose RECORD first and play the game as well as you can. When done recording press all 4-arrow keys together. Return to your code and Press CTRL+V to paste the new btnpb (button playback) string. Then select the PLAYBACK function instead of record, run the code, and sit back and watch it.

If you want to, paste your own Pico-8 cart playing back your own movements for the game, to show everyone else how well you can play it.

If greater compression over raw numbers is desired, (6-bit characters for instance), I can certainly write that for you and increase the btn() function in size slightly with higher compression in the data table.

Thanks to @Cadaeib65 for getting my brain spinning on this.

Hope This Helps !

P#105249 2022-01-17 21:47 ( Edited 2022-02-26 07:05)

why isnt this playable

P#105258 2022-01-17 21:55

Brobgonal cause that's the point.
Also this is sick! I would love to make a TAS for my game and watch it back or something hahaha

P#105259 2022-01-17 21:57

Hi @brobgonal. That is the point. It is the first time to be able to take over the controls of Pico-8 and play them back as someone can record them, in this case what you see above is me playing the level.

If you own Pico-8, you can play this game from your DEMO folder. Failing that @zep did post the original JELPI found HERE:


P#105260 2022-01-17 22:05

Hi @SmellyFishstiks. Thanks ! I was beginning to wonder if what I wrote would not be understood.

And yes you can take those few functions, put them in your code, record a speedrun, press the 4-arrow keys to exit. Choose a line of your code to paste the playback string.

Select playback() post the new cart in your same or different thread, and you are all set. Let me know too ! So far I've only seen my playback code for JELPI.

Truly @zep should already have this feature of record and playback built-in. This, rewind, frame forward, frame backward, cheat search, save state, and load state.

P#105261 2022-01-17 22:09 ( Edited 2022-01-17 22:09)

Ya I'll have to see if it works on other carts, I'm not sure that a feature builtin to pico like this would be what I want but ya it's fun to play with.

P#105264 2022-01-17 22:18

Yes, please let me know, @SmellyFishstiks. I want this to work properly all the way around. I know there are some Pico-8 games people really do want to speedrun, and hopefully this tool will help in that endeavor.

P#105265 2022-01-17 22:22

this is sick!

P#105268 2022-01-17 22:35

Thanks, @SandwichBlam. I'm hoping someone posts a CELESTE or modified CELESTE speedrun cart with it. I think that would be interesting to see - and would verify my program is working 100% correctly.

P#105269 2022-01-17 22:39 ( Edited 2022-01-17 23:01)

This is like handing your little brother the controller because he wants to play but it isn't plugged in so he just watches you play thinking he's playing

P#105272 2022-01-17 23:10

Ah, pretty well, Scrub. I was thinking of flashing a green or red light or something in the corner showing recording or playback, but that might interfere with gameplay.

If it's truly desired, I can add it.

I wrote this so it would help others post a speedrun of their favorite games. Or maybe even nail down a particularly tricky bug that only appears one way.

You record up to that point where it crashes, post your recorded keystrokes. Then give that text or cart to someone where it dies and they can easily track and trace the problem by watching the playback.

As mentioned, adding this ability inside Pico-8 I think would be beneficial and increase interest in using it over other more limited free Fantasy Consoles.

P#105274 2022-01-17 23:44

hmmm I tried it with my game to start like this:

-- [[ game playback recorder
 --written by dw817 (01-17-22)
 --standard ⌂ pico-8 license

 function record()

 function playback()



 -- call btn() as normal
 function btn(p)local b=_b0()if _bm==1then if b!=_bl then if _bd>""then _bd=_bd.._bt..","else _bd=""_bt=0_bp=1end _bl=b _bd=_bd..b..","_bt=0else _bt+=1end if _b0()==15then printh("btnpb={"..sub(_bd,1,#_bd-1).."}\n","@clip")stop()end return _b0(p)elseif _bm==2then if _bt>0then _bt-=1else _bs=btnpb[_bp]_bt=btnpb[_bp+1]_bp+=2if _bt==nil then _bm=0end end if band(_bs,2^p)>0then return true else return false end else return _b0(p)end end

And at first I wasn't realizing why it wouldn't end recording when I pressed down ⬅️➡️⬆️⬇️,
Then I realized that you have to have a btn() call I guess which doesn't get ran when the player dies.
But after I figured that out I put my btnpb in and it keeps on giving me this error:

runtime error line 31 tab 0
 function btn(p)local b=_b0()if _bm==1then if b!=_bl then if _bd>""then _bd=_bd.._bt..","else _bd=""_bt=0_bp=1end _bl=b _bd=_bd..b..","_bt=0else _bt+=1end if _b0()==15then printh("btnpb={"..sub(_bd,1,#_bd-1).."}\n","@clip")stop()end return _b0(p)elseif _bm==2then if _bt>0then _bt-=1else _bs=btnpb[_bp]_bt=btnpb[_bp+1]_bp+=2if _bt==nil then _bm=0end end if band(_bs,2^p)>0then return true else return false end else return _b0(p)end end
attempt to perform arithmetic on local 'p' (a nil value)
at line 0 (tab 0)

where p is nil.. so ya It's really cool but man I just don't know how to use it.

(this was in the bottom of init. though I tried elsewhere and got the same issue)

P#105282 2022-01-18 01:24 ( Edited 2022-01-18 01:26)

ya when printing out p the first one is always nil..
OH wait, this is cause I have a btn call somewhere that's just nil or something isn't it

if btn()~=3 and (btn(0) or btn(1)) or a.drilling then
  a.ifmove = true
  a.mt += 1

ya I have this. is there anyway you could make a failsafe if a btn() call doesn't have any arguments and is just for getting the bit field?

function btn(p) if p then local b=_b0()if _bm==1then if b!=_bl then if _bd>""then _bd=_bd.._bt..","else _bd=""_bt=0_bp=1end _bl=b _bd=_bd..b..","_bt=0else _bt+=1end if _b0()==15then printh("btnpb={"..sub(_bd,1,#_bd-1).."}\n","@clip")stop()end return _b0(p)elseif _bm==2then if _bt>0then _bt-=1else _bs=btnpb[_bp]_bt=btnpb[_bp+1]_bp+=2if _bt==nil then _bm=0end end if band(_bs,2^p)>0then return true else return false end else return _b0(p)end end end

maybe not the best way but something like that?

P#105283 2022-01-18 01:29 ( Edited 2022-01-18 01:32)

Hi @SmellyFishstiks:

Can you post the entirety of the code, please ? Full cart. I'll see what I can do to get it working and recording/playing back correctly. And yes I likely need to write a function for BTNP() as well.

Currently my record/playback engine only works with BTN(), not BTNP() nor any mouse functions.

P#105284 2022-01-18 01:31

ya I was editing my msgs to not spam, it was a lose btn() check but like ya could there be a failsafe?
When I added that failsafe it works now

P#105285 2022-01-18 01:32 ( Edited 2022-01-18 01:33)

I think I understand, @SmellyFishstiks. You want to be able to call btn() with no arguments and it returns the correct value instead of TRUE or FALSE.

Let me examine my code.

P#105286 2022-01-18 01:36

ya I want to use btn() by it's self to get just the state of the buttons, I use this as a cheap way to make sure you aren't pressing left and right at the same time.
And I'm sure I'm not the only one that has used this either

P#105287 2022-01-18 01:38 ( Edited 2022-01-18 01:38)

OK, rather than change all the code, @SmellyFishstiks, replace this single line into yours to see if this fixes it:

function btn(p)local b=_b0()if _bm==1then if b!=_bl then if _bd>""then _bd=_bd.._bt..","else _bd=""_bt=0_bp=1end _bl=b _bd=_bd..b..","_bt=0else _bt+=1end if _b0()==15then printh("btnpb={"..sub(_bd,1,#_bd-1).."}\n","@clip")stop()end return _b0(p)elseif _bm==2then if _bt>0then _bt-=1else _bs=btnpb[_bp]_bt=btnpb[_bp+1]_bp+=2if _bt==nil then _bm=0end end if p==nil then return _bs elseif band(_bs,2^p)>0then return true else return false end else return _b0(p)end end

If it does, I'll update the master.
Master cart updated.

P#105288 2022-01-18 01:42 ( Edited 2022-01-18 02:38)

It seems to work, Though after watching this I see as well that the rng state could mess things up (ex the clouds.)... would have to save the seed you started recording on and srand at the start..
But for replaying stuff this works great, Will love to use it if I have enough tokens left to record runs and stuff.

P#105289 2022-01-18 01:59

Owow I love your Rescue Bird, @SmellyFishstiks. That is neat. I am totally in the field I want to be. Helping out game programmers with useful functions and utilities. :)

As for tokens, hmm ... I could write a function that waits until you press CTRL+V and then PASTES the playback script from the clipboard directly into the array - skipping adding it to the source-code, if you think that will help.

. . .

Let me update the main engine with this new function.

P#105291 2022-01-18 02:20 ( Edited 2022-01-18 02:21)

ya new version works. once I actually have stuff to do in my game it'll get interesting.. But ya cool tool thanks for making it

P#105294 2022-01-18 02:44

You are very welcome, @SmellyFishstiks. I hope you other guys and gals find it useful too. I'm - already working on something else. :)

Write if you have any questions or comments about this Playback project.

P#105296 2022-01-18 02:47

Oh my god thank you so much @dw817 ! I will ask you again later when I have PICO-8. Do you have a discord or smth that we could use to not flood this place ? By the way I don't think the game I want to TAS has any RNG.

P#105300 2022-01-18 05:47

I'm glad you like it, @Cadaeib65. :) Something overdue for Pico-8 I guess ...

I was on discord at one point. Understand I'm never a leader. I always try to follow - if the path is not too difficult. If you yourself open a Discord I will accept your invite - but I won't open one personally myself.

Or you can reach me on my Writer's page by creating an account there for messaging. Click dw817 on this page to see the link. Click that link, let the page come up, then click at the top right, "Sign Up!" Once logged in you can send and receive private mail. I read, write, and reply to messages on that site daily as it's my home on the internet.

That's the best I can do.

P#105302 2022-01-18 06:33 ( Edited 2022-01-18 06:46)

There is is pico-tas discord I discovered recently @dw817 https://discord.gg/JWvDMda2

P#105507 2022-01-22 11:35

Received invite, @Cadaeib65. Thanks !

P#105525 2022-01-22 20:59

I like your colour taste. The game is not only properly programmed(I guess) but also looks fantastic.

P#105575 2022-01-24 19:30

Hi, @WallacePrio. Thank you however this game is not mine. It is from @zep, our lord and master of Pico-8.

What I wrote here is a way to record your movements and play them back in any Pico-8 cart, especially for use in Speedrunning. That is all.

P#105581 2022-01-24 22:34

I can't get the code to work, can you help me understand what to do?

edit: nvm, my keyboard won't register all four keys at once so I changed it to the enter key
edit2: still not working :(

P#112382 2022-05-27 12:23 ( Edited 2022-05-27 12:56)

Does anyone know why it is not properly recording my buttonpresses?

P#112386 2022-05-27 15:24

@dw817 can you please help?

P#112434 2022-05-29 09:00

Hi @Sup3rAw3som3Gam3r:

First off be certain that the statement, b0=btn is NOT included in any function, not even INIT. Have it as the very first line of your code if you like.

Let me know if you're having problems after that.

P#112439 2022-05-29 14:46

just to make sure I didn't do something stupid, can I paste this into a cart to add recording to it?
edit: oh wait, I maybe got it working!!!

P#112444 2022-05-29 15:21 ( Edited 2022-05-29 15:24)

Can you explain the numbers? I want to try to do tas with this
(just for fun)

P#112445 2022-05-29 15:28 ( Edited 2022-05-29 15:28)


Did you get it working to your satisfaction ?

The numbers are merely the button presses combinations and the durations they are pressed. It's pretty straight-forward.

P#112459 2022-05-29 22:18

I don't understand how the delays and stuff (for example, there is no btnp(16) in pico-8)

P#112461 2022-05-29 22:56

superawesomegamer pico8's button input is a byte that holds a bit field of the button presses per player
(you can test this by doing print(btn()) )

P#112462 2022-05-29 23:19 ( Edited 2022-05-29 23:20)

how is duration saved?

P#112463 2022-05-29 23:32

Hi @Sup3rAw3som3Gam3r:

Duration is saved as the 1st number.

P#112493 2022-05-31 00:50

ahh, thanks

P#112496 2022-05-31 01:02

You're very welcome. Here now, please show me a playback of some game you have in mind for this. I'd like to see that. Thanks !

P#112497 2022-05-31 01:03

setting the stop key to tab is helpful for me
(also, it seems the 2nd num is the dur)

P#112499 2022-05-31 02:31 ( Edited 2022-05-31 02:32)

That could be, @Sup3rAw3som3Gam3r. I just kind of fired and forgot the code. Playback code is good for action games, not turn-based so it's not something I am going to use a lot of.

I can examine the code, but if you are already making mods then I think you see how it works.

And good for that ! Still though, let me know when you get a video or P8 all done for playback for one of your games. It would be interesting to see my code in use for something you wrote.

P#112500 2022-05-31 02:56

60 fps so testing is faster but:

P#112501 2022-05-31 03:19

Wow ! Pretty good use of the playback. It's a shame you can't actually edit P8 videos in Pico-8 - or to control frames forward and backwards during actual execution.

I was going to develop something like this yet it would be pretty limited. Still, a programming language that can run both forwards and backwards would be a treat indeed.

P#112502 2022-05-31 03:54

Can you record RNG?

P#141055 2024-02-03 01:48

[Please log in to post a comment]