Log In  

My question(s) is, what is the best way to store level data and/or do you need a special PICO-8 level editor to do that? I am asking because I'm currently making a game with more levels than one map can handle.

P#89899 2021-04-03 03:42

Hmm well there's lots of ways to go about it since you could use any part of memory or the code space to store arbitrary data.. but I think a method that could work that i've tried (I'm still noobish though.) is to use the map data to encode more than 1 tile per. so like you read the map data as 1 tile per 2 and then you use all of the tiles to store half of the possible tiles in 2x less space etc. but I'm sure there's better ways to go about it and ya since the data is just a list of numbers it would make sense to make a tool (but not needed.) to visually show the tiles and then output the mapdata.

Also PS: some people use the spritesheet pixels to encode mapdata, this is the same thing as the memory thing I said but I guess this way you could use sget and such which might be nicer than the alternative of peeking.

P#89902 2021-04-03 03:57 ( Edited 2021-04-03 03:58)

Thanks for the info, even though I don't know how to do that, I was originally thinking about using tables since I think have more than enough tokens (5008/8192). An example is shown below

leveldata1 = {1,4,2,3} --insert level data into this table
leveldrawtile=0
for leveldrawnum in all(leveldata1) do
 poke(leveldrawtile+8192,leveldrawnum) --draw the tiles to the map
 leveldrawtile+=1
 map()
end

Make sure you add these sprites in
[8x8]
[8x8]
[8x8]
[8x8]

P#89904 2021-04-03 18:24

You can save a lot of tokens by replacing the first line with
leveldata1 = split"1,4,2,3"

P#89931 2021-04-03 20:00

Wow @Profi06, that really will save a lot of tokens!

P#89933 2021-04-03 20:36

How do you read the memory though (I already have carts that have the level data)? I've tried many attempts at using PICO-8's code to get the data for me but nothing is working.

P#90150 2021-04-08 00:45 ( Edited 2021-04-08 00:50)

Pico’s code?
Pico has a memory and you can use peek() and poke() and some others like peek2/4() and memcpy to manip it.

P#90151 2021-04-08 00:49

I've been trying with normal peek but it's not working.

--an example of an attempt that did not work
anumber=0x1fff
while anumber<0x2fff do
 anumber+=1
 avalue=peek(anumber,8192)
 add(mapdata,avalue)
end
--returns 0 as table even with full mapdata in cart ¯\_ (ツ)_/¯
P#90152 2021-04-08 00:51 ( Edited 2021-04-08 01:26)

peek only takes 1 argument and also it works for me.

cls(1)
palt(0,false)
pal(0,7)
for i=0,130 do
 poke(0x2000+i,1)
end

map()

?peek(0x2040),13
P#90158 2021-04-08 01:49 ( Edited 2021-04-08 01:52)

It's not working for me.

cls(1)
palt(0,false)
pal(0,7)

map()

mapthings=peek(0x2040)
printh(mapthings,'@clip')
--still copies 0
P#90159 2021-04-08 01:53 ( Edited 2021-04-08 01:57)

At least if we do figure this out then both of us can use it @SmellyFishstiks

P#90162 2021-04-08 02:04
3

I've actually just made a set of functions for compressing both sprite and map data to strings. The decompression function is very small at just 96 tokens, and from comparisons I've done, it's usually fairly close in compression ratio to Zep's PX9 system, which takes up several hundred more bytes in size and uses 254 tokens. It seems to compress dense maps around 2:1, and more sparse ones can compress up to around 6:1 or 7:1.

The functions should be pretty straightforward, you'll just need to make sure you're in puny font mode before you paste the strings the compressor makes, or things won't work right. Also, this will let you use sprites 0-239 in your map, or all but the last row of the spritesheet.

--Specify mget for map or sget for spritesheet, and width and height
--of area to compress. Right now it's set up to have the top left
--corner of the map or spritesheet as its starting point.

function compress(get,w,h)
 s=chr(w+96)
 local function fix(v)
  if(v==18) v=-2
  if(v==76) v=-1
  return v
 end
 local n,len,k=0,1
 while n<w*h do
  local val,nxtval=get(n%w,n\w),get((n+1)%w,(n+1)\w)
  if nxtval==val and len<159 then
   len+=1
  else
   if len<=14 and get==sget then
    s..=chr(fix(val+len*16)+16)
    k=1
   else
    s..=chr(fix(val)+16)..chr(len+96)
    k=2
   end len=1
  end n+=1
 end
 if(k==1) s..="-"
 printh(s,'@clip')
end

--specify string name, mset or sset for map or sprite, and location in 
--map or spritesheet where you want data decompressed to

function decompress(s,set,x,y)
 local i,n,w=2,0,ord(s,1)-96
 while i<#s do
  local v,l=ord(s,i)-16,ord(s,i+1)-96
  if(v<0) v=134+v*58
  if(set!=mset and v>15) l=v\16 i-=1
  for j=1,l do
   set(n%w+x,n\w+y,v) n+=1
  end i+=2
 end
end
P#90164 2021-04-08 02:29 ( Edited 2021-04-08 02:33)

O_o I now realize that I'm a total noob at PICO-8. Also thanks for the info @JadeLombax!

P#90165 2021-04-08 02:35

You're welcome, just let me know if you have any problems using the functions.

P#90167 2021-04-08 02:48

Uhh, wait. What is puny font mode and how do you enable it?
(Sorry, specified coding isn't my thing.)

P#90168 2021-04-08 03:07 ( Edited 2021-04-08 03:08)

Oh, it's a Pico-8 thing. To enable small capital letter characters to show up in the code editor, you have to press Ctrl+p. If you try to run the decompression function without doing this, large letters will be substituted in the data strings and the sprite or map data will get scrambled.

It's a bit of a pain, but doing things this way let me store almost a whole byte per character and keep the decompression function small and simple.

P#90169 2021-04-08 03:16 ( Edited 2021-04-08 03:23)

Cool, also can you explain what each main variable is (the program keeps asking me to add values to nil variables).

P#90170 2021-04-08 03:24

Also @JadeLombax, you're like a fountain of knowledge for me. I probably wouldn't have figured out the compression for probably a couple of years! I will make sure that you get credited when I use this in Super Mario Remix (see here: https://www.lexaloffle.com/bbs/?tid=39432). Furthermore, is there any way I can return the favor (sprites or music)?

P#90171 2021-04-08 03:32 ( Edited 2021-04-08 03:33)
1

For the compression function:

get = sget or mget (reads sprite or map data)
w = width of sprite pixels or map tiles to compress (starting at 0)
h = height of sprite pixels of map tiles to compress (starting at 0)

For the decompression function:

s = name of data string to decompress
set = sget or mget (writes sprite or map data)
x = starting x position in in spritesheet or map to decompress to
y= starting y position in in spritesheet or map to decompress to

So to compress the whole 32 screens of the map to a string, you'd enter

compress(mget,128,64)

Then press Ctrl+P to enter Puny font mode, paste the string, name it (such as mapdata=".....")
and enter the following to decompress it

decompress(mapdata,mset,0,0)
P#90172 2021-04-08 03:41 ( Edited 2021-04-09 17:39)

A HUGE thanks! This will really help me on my journey in game design!

P#90173 2021-04-08 03:45

That's alright, I've just noticed you on the boards trying to figure out how to fit more levels in a cart for a while, and my metatile map editor, which you asked about a while ago, has ended up taking longer to finish than expected. I've got it working just fine this point, but I just finished improving the map and sprite compressor here so it would be more capable and versatile, and I'm working on a tutorial to teach people how to use the system, since it's a bit complex.

I think the compression function could be useful to people who want a bit more space but aren't making an NES-length game, or who aren't necessarily ready to switch to a new map editor.

All that said, I haven't really made any music yet, so I might ask you about that sometime ;).

P#90175 2021-04-08 03:50 ( Edited 2021-04-08 04:01)

... ok well I'm just going to ignore that and be on my way, poke and peek can take a sec to understand.

P#90176 2021-04-08 03:55

Ok then, I'm happy you're not mad or anything.

P#90198 2021-04-08 12:00

If you need a way to make maps in the meantime, you could just create a separate a cart for each map, hand it just a simple line of code to call that compress() function, run it, and then paste the results into your main cart. That way you can still use the map editor as normal for actually creating the maps. As a side benefit, that also would make it less likely that you lose a map because of overwriting or because of a screw-up while using JadeLombax's system.

P#90251 2021-04-09 07:11
:: merwok

It’s even possible to have these separate level builder carts write their result not to clipboard but to a file ('printh(string, "level1.p8l"'), then use '#include level1.p8l' to get the data automatically!

P#90280 2021-04-09 15:00

@kimiyoribaka I'm already doing that.
@merwok That would be a good idea if my computer hardware was lacking but it isn't and I'm not too keen on creating a lot of almost empty carts for this project.

P#90362 2021-04-11 17:37

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2021-04-17 09:05 | 0.177s | 4194k | Q:67