Log In  

so, i'm planning on doing kind of a demake of rhythm heaven(with new minigames cuz, nintendo y'know?) but i don't think a single pico cart would be able to hold all music/sprites (i've only been able to hold 8 songs w/ pic-o-beat)
i've been looking around and i saw some options but i have no idea on what would work better for me, this is what i found so far:

compression: there's a lot of code about this here on the bbs that i find fascinating, but have zero idea on how it works to make it do the songs intead of the spritesheet

load a cart per stage: have a main menu cart and load each stage in different carts, the loading isn't great but if it's the best way to do it its allright

load only the music and spritesheet: i remember seeing this somewhere but i can't find it anymore, i imagine the loading would be quicker, and i could easily reuse mechanics between minigames but i have no idea on how to do it

a ton of peeking and poking: have a main cart with all the song and sprite data that "set up" the data on a series of "cartdatas" that can be memcpy-ed at runtime. this would allow community submissions with, i imagine, little to no difficulty but would be really awkward for the user

probably some really simple stuff idk about: if you know, please tell me

P#89584 2021-03-26 01:54 ( Edited 2021-03-26 02:53)

:: merwok

There are many examples on the bbs about compressing (not encrypting! that’s something else) data for sprites or map, these are easier examples because we can use the functions 'sset' or 'mset' to get the decompressed data into our target zone (spritesheet or map). For SFX and music we only have functions to play them, not to get or set data! That means you have to read up on memory access in pico8 (see the unofficial wiki), manipulate bits to make bytes, and use the peek functions to write these bytes into the region of the memory that stores SFX or music.

Chain-loading carts (using 'load') is certainly the easiest option for bigger games. Each cart has its own assets and its own code; if you need the same code in all levels you can use 'include' to avoid having to copy it, you can write it in one tab of one cart and include that tab automatically from the other carts. This works with real pico8, on the BBS, in HTML or binary exports.

Multi-cart (using 'reload', one cart with code and data cards with only sprites/map/sfx/music) is the second easiest, but doesn’t work on the BBS (which also feeds splore!), so that’s no fun. If I remember correctly, reload doesn’t have the little loading time and icon that load has.

P#89591 2021-03-26 02:45
:: Ningow

Thanks a lot, i always get compression and encryption mixed up sorry. i think i'll go with chain-loading then, i didn't know multi-cart didn't work on bbs so that's a no-go.
i'll try and make a test cart to see the cartdata storage idea in action, but i don't think id be that useful (you'd need to do it 32 times for a full spritesheet and 17 for the music, but depending on how that goes it might be good for player generated content as it can be used in many carts)

P#89592 2021-03-26 03:09

The multi-cart method (reload()) is intended to be the easiest option for the specific case of loading more graphics or sound assets from other carts. You can edit those assets directly in PICO-8 in those other carts, then just reload() the appropriate memory region from those files. For example, to load the entire music and sfx region from another cart:

reload(0x3100, 0x3100, 0x1200, 'data2.p8')

(It does use the artificial delay with the spinning cart icon, I just tested.)

If you want to involve compression, then you have to manipulate that memory after it is loaded. This also requires a more complex workflow where you edit the raw assets, then compress and export the data to the cart.

Yes reload() won't work from the BBS and doesn't work with BBS ID filenames (#xyz-1). It does work with the web and binary exports. One option is to export the multi-cart as a web player, upload it to itch.io, then post to the BBS with either just a link to itch.io, or perhaps a "demo" version of the game with the first level and a link to the full game. It's not perfect but it's something.

export mygame.html data1.p8 data2.p8

(I imagine BBS support for multi-carts is low on the priority list, but maybe people would make more multi-carts if the export options were more complete?)

P#89593 2021-03-26 06:34
:: merwok

Thanks for the corrections!

I think multi-cart is not supported in the BBS on purpose.
Carts on the BBS are part of the cartverse, directly accessible using splore from pico8 consoles that are connected to the internet, so zep wants them to follow the constraints he imagined for pico8, and encourage us to focus on mecanism rather than content. We have reload multi-cart to make bigger standalone games, but I think that’s pico8 the modern game engine and not pico8 the cozy retro console.

P#89613 2021-03-26 14:59
:: Ningow

so, turns out that cartdata() can only be called once lmao

P#89639 2021-03-26 22:30

cartdata() is for persistent storage, 256 bytes of base RAM starting at memory address 0x5e00 and intended for data such as settings, progress or saves. Not to be confused with cartridge ROM where sprites/map/sfx/songs are stored, or the corresponding first part of base RAM (up to 0x4300), into which cart ROM gets loaded for use.

I think part of your difficulty is that you've been scrounging the bbs looking for compression, i.e. squeezing a specific amount of data to fit into a smaller amount of memory. This is quite well explored for sprites and map data: a variety of image and text compression techniques, well-known in computer science, lend themselves to the problem. Not much for songs though. (yet?)

But even without compression, it is still possible to simply encode data and store it somewhere other than cart ROM:

  • 0.2.0i gave us pack() and unpack()
  • 0.2.1 gave us split()
  • 0.2.2 introduced multipoke, multiple (up to 2048) values can be read/write at once, so "a ton of" peeking and poking is no longer needed -- you can do a lot in one shot.

This provides the tools needed to take any data, including song/sfx data, and encode it as a string. The string encoding can then be included in the lua code of your cart, and decoded and written back into base RAM as and when needed.

For example, see the section about custom fonts in the 0.2.2 announcement post. The #FONT_SNIPPET cart is an encoding tool that grabs font character data from the spritesheet and encodes it as a string, then outputs a snippet that looks like these. The long string of numbers, separated by commas, is the encoded representation of the custom font data: each number (0~255) is one byte. The string is many characters long, but counts as just one token; it takes 6 more tokens to decode the data (split, unpack) and dump it (poke) into the intended destination address at 0x5600.

In this way, although there is no provision to store custom font data in cart ROM and space for only one custom font in base RAM at any time, it is possible to have several different custom fonts encoded as strings in lua code and to switch between them as desired.

Same principle can be applied to expand the amount of music you can have on your cart; you can even have a table/list of multiple strings where each one is a song, and reuse the same decode+dump code for all of them. This method is limited only by lua character and token limits. Using pic-o-beat for reference, it is at 3990/8192 tokens and 16631/65536 chars, so there's plenty of room to expand it beyond more than just 8 songs if you wish.

Given that each encoded string is just one token, and the code overhead is also very low, it's more likely that the character count would be the predominant limiting factor for how many songs you can cram into lua. And to help with that, there is one more trick we can bring to bear: instead of encoding bytes as numbers separated by commas (density: one byte per 2-4 characters in the string) we can use ord()/chr() to map byte values to P8SCII characters (since there is now a full set of 256). That requires no commas as separator, and has a density of almost one byte per character (some characters need to be escaped in lua). The snippet for that is here.


P#89854 2021-04-02 12:33
:: Ningow

That's actually perfect for the rhythm heaven case as they pretty much only change the visual and audio stuff with very few code differences, so the chars are free for encoding, and we could use the whole(or at least a big part) of the music to chart the little subtle differences and avoid boring repetition
Thanks a lot!

P#89938 2021-04-03 22:03

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2022-09-30 20:21:02 | 0.006s | Q:15