drakeblue [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=47206 Saving Tokens <p>These are my own notes on saving token tricks that I've used previously. I'm sure what's here is not unique to me - there are other documents about this subject (e.g. <a href="https://github.com/seleb/PICO-8-Token-Optimizations">https://github.com/seleb/PICO-8-Token-Optimizations</a>) and I recommend looking at those as well, probably before this one. I intend to add and update here as I learn more.<br /> If you see a mistake or are a true wizard that can offer wisdom to this humble novice then please feel free to comment :)</p> <h1>Starting out</h1> <p>I say &quot;starting out&quot;, because the next few ideas concern initialisation and structure, but this might be a good place to suggest that a lot of these tips produce much nastier to read code that's more of a pain with which to work and employing all this stuff straight away, especially if you're new to coding is just going to make the whole experience more difficult and probably not much fun. I tend to bear some of the things here in mind as I code and some things are becoming (bad) habits, but usually I've only used these techniques as a second, third or an in desperation when PICO-8 won't run any more pass.<br /> Coding your game in a more elegant way or even... cutting things(!) that aren't necessary are probably both better ways to save tokens.</p> <h2>Functions or &quot;to _init() or not to _init()&quot;</h2> <h4>3 tokens; 19+ characters</h4> <p>I don't use this function at all and do all initialisation at the end of my code, that is, after any other function definitions (so that they're not undefined if calling them from the initialisation code). If you're using the PICO-8 editor I'd suggest putting it in your rightmost tab.<br /> I'm going to end up using global scope anyway and I have yet to find a downside.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function _init() my_var=1 end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>my_var=1</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Initialising variables</h2> <h4>1 token per variable</h4> <p>Every time an '=' is used a token is wasted:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,b,c=1,2,3</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(7 tokens)</p> <p>vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a=1 b=2 c=3</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(9 tokens - 1 for each '=')<br /> To make this (a bit) nicer to deal with I tend to do something like the following when this kind of list gets very long (often longer than shown here):</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,b,c,d= 1, -- a 2, -- b 3, -- c 4 -- d</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This uses the same number of tokens and I've had to resort to code minification that will remove the comments, newlines etc. for the last few projects anyway. I use this one, which is great BTW: <a href="https://pahammond.itch.io/gem-minify">https://pahammond.itch.io/gem-minify</a>.</p> <h3>Aside - assigning nil</h3> <p>Need to clear a variable to nil (which conveniently evaluates as false - todo: more on booleans)?</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,n=1</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>4 tokens</p> <p>vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a=1 n=nil</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>6 tokens</p> <p>Pretty desperate and calling a non-returning function after your variable assignment?</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>n=nil nil_returning_function(&quot;some text&quot;,0,0,10)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>9 tokens<br /> vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>n=nil_returning_function(&quot;some text&quot;,0,0,10)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>8 tokens<br /> WARNING: You need to be <em>very</em> sure that the function doesn't return anything. I got caught out by this myself writing this post as I initially used print as an example here and as GPI points out below it <em>does</em> return a value. You need to be very desperate to do this as it really, really doesn't help with code readability and is asking for trouble if you, say, change the function to return a value at a later data. But if you're right up against the token limit...</p> <h3>Back on initialisation - split() is your friend</h3> <p>Got a lot of strings you want in a table?</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>tab={'baa','baa','black','sheep'}</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>7 tokens<br /> vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>tab=split('baa,baa,black,sheep')</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>5 tokens<br /> vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>tab=split'baa,baa,black,sheep'</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>4 tokens</p> <p>Don't use brackets for function calls or maths unless you have to, since they add a token for each pair that you use.<br /> Note: the following is perfectly legal in lua:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>rnd{1,2,4,8}</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(This returns a random value from the table {1,2,4,8})</p> <h3>unpack is also your friend (and itself friends with split)</h3> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,b,c,d= 1, -- a 2, -- b 3, -- c 4 -- d</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>11 tokens<br /> vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,b,c,d=unpack(split'1,2,3,4')</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>10 tokens</p> <p>Further variables cost 1 token each i.e. each further variable you add to a statement like this will save a further token compared to the version above (and 2 compared to separate a=1 b=2 etc.)<br /> Be warned, you may have trouble with your variables being initialed as strings, but pretty much every PICO-8 function I've tried (e.g. spr, print, rectfill, pal etc) Just Works. The problems I've had with this have been my own code. It's also very hard to know which number corresponds to which variable so I suggest only using this trick when you really need to.</p> <p>Of course, you can go further:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,b,c,d=unpack_split'1,2,3,4'</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>8 tokens*</p> <p>The caveat here is, obviously, that you need a function like:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function unpack_split(...) return unpack(split(...)) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>10 tokens by itself.</p> <p>However, once you have that function...</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>print(&quot;hello world&quot;,10,20,11)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>6 tokens</p> <p>becomes</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>print(unpack_split&quot;hello world,10,20,11&quot;)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>4 tokens</p> <p>It's remarkably fast - I found that I only hit performance trouble if I used it within nested loops or with very high numbers of objects.</p> <p>In fact, every time you have 3 or more literal values together you can save at least a token with your unpack_split function anywhere in your program (it's a flat cost for each use in fact). I used it enough that I ran into trouble with the number of characters it used and the compressed size limit - renaming the function to US or similar solves that fairly nicely, once again at the cost of making the code ever less readable.</p> <h3>Order is everything</h3> <p>Armed with these techniques the next thing to consider is <em>when</em> to assign values in you initialisation (or anywhere else).<br /> The more you can bunch together, the better since e.g. fewer '='s are needed that way and you can group more literals into a single unpack_split'1,2,3,4'. Remember you can't reference an assigned value from within the same assignment though.<br /> This doesn't work (unless you really want y to be what x <em>was</em> previously + 3):</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>x,y=20,x+3</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>todo: add multi-dimensional table routines</p> <h2>Example from PICO Space</h2> <p>Stare into the void if you're feeling brave enough...<br /> <div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>g_part_expl,g_vel,g_rand_cloud,S,g_sun_pal, g_candy, Sc2, g_syls, g_scpal_map, C, g_news, M, D, U, g_ratings, g_npc_chat, g_diff, g_diffs,g80,g81, ss1,ss2,F,-- start of literals g_near,g_far,g_edge,g_msp,g_gal_size, g_gal_time, g_fin, g_sys_p, Q,--g_progress? g_award, p, g_music, g_gal_seed, g_sys, O, g_cmdr, g_kills,g_max_energy = {vel,vel,rand_cloud},{vel},{rand_cloud},--g_part_expl {c=8,sp=.3,en=8,dam=1},-- ship { --g_sun_pal split&quot;10,9,8,4,2&quot;,-- yellow split&quot;7,10,9,8,2&quot;,-- white/yellow split&quot;7,12,13,15,1&quot;,-- white/blue split&quot;7,6,13,5,1&quot;,-- white/grey split&quot;12,13,15,5,1&quot;,-- blue split&quot;7,11,3,5,1&quot;,-- white/green split&quot;10,11,3,5,1&quot;, --yellow/ green }, split&quot;10,12,11,8&quot;,--g_candy split&quot;0,1,1,2,1,5,12,2,4,8,3,15,2,2,1&quot;,-- Sc2 split&quot;ca,bal,da,gar,non\-en,pol,der,arp,bun,duc,kit,poo,v\-evee,zir,buf,v\-evil,xan,frak,ing,out,re,far,do,tel,tri,cry,quack,er,dog,pup,sno,ger,bil,pa,n\-ena,jan\-en,es,on&quot;,--g_syls {[0]=0,unpack_split'0,1,1,2,1,13,6,2,4,9,3,15,5,4,1'},--g_scpal_map {x=0,y=0},--C { -- g_news gal={ split_comma'president #2 welcomes gerbil delegates to the #1 galaxy on state visit.|government says there are no broccoli or carrot shortages.|vice-president: reports of space weevil incursions are fake news and no cause for alarm.|recipe book by great aunt dahlia using substitutes for carrots and broccoli returns to bestseller chart, four hundred years after first edition|cats complain that kangaroo boxing title challenger hit their reigning champion, &quot;she is supposed to sit in the boxes not punch other animals&quot; ', split_comma'president dismisses rumours of a weevil invasion.|&quot;no carrot shortage,&quot; says vice-president, &quot;just eat a potatoe instead&quot;|duck wins round-galaxy race by a bill from bunny. bunny claims galaxy is not round.|president #2 denies spending entire security budget on jacuzzi: &quot;no-one will attack us anyway and i like the bubbles&quot;.|dog moral philosophy professors to discuss exactly who, if any of them, is a positive young male role model and also the location of &quot;it&quot;|bears win hugging title for twentieth year running', split_comma'&quot;things are not getting worse,&quot; says president despite weevil presence noticeably increasing.|carrots vanishingly scarce as prices rise sharply. rabbits lobby parliament|&quot;has anyone actually met a weevil?&quot; asks vice president|government officials deny that gerbil delegates left because of weevils eating their carrots|&quot;#1 shall have a universe-beating track and trace system for the weevil incidents,&quot; says #2|rhinos record victory in world rugby championship against mice team who have never qualified previously, but had elephants running scared in previous game', split_comma'president #2 says: &quot;we are following the best scientific advice on the weevil problems,&quot; despite no obvious actions being taken|top military advisers say, &quot;this is not the time to panic, but it could be soon.&quot;|&quot;i grew my own broccoli,&quot; says mouse, &quot;but weevils stole and ate it.&quot;|reports of weevils in almost every system.|what is your family doing to cope with the weevil invasion?|princess macaroon wins jousting tournament for sixth year running despite many jousters staying away due to weevils, &quot;i could joust the weevils too,&quot; says macaroon', split_comma'#1 becoming overrun by space weevil menace.|what do the weevils want? beeb news asks the experts.|raccoon caught selling parsnips dyed orange as fake carrots says &quot;most animals never even noticed.&quot; could you tell the difference?|frog croaking championship described as &quot;riveting&quot;|vice president distributes personal broccoli to poor parrots. parrots respond saying they &quot;do not eat the stuff&quot;.|our reporters present 10 tips to cope with a hostile invasion from another species in style|snakes record first win in football. defeated lion captain said after the match: &quot;they really used their heads&quot;.', split_comma'president #2: &quot;we did everything we could to stop weevils, but it has been an unprecedented situation&quot;|top military advisers say &quot;this is the time to panic!&quot;|&quot;we need a hero,&quot; says panda, &quot;someone should find the weevil base and take out the queen weevil.&quot; who could possibly do that?|president and vice-president still say carrots and broccoli supplies are fine - does anyone still believe them?|&quot;i, for one, welcome our new weevil overlords,&quot; says president #2|giraffe sees image of dog in his breakfast toast|panda says he is tired of people expecting him to pursue car thieves in his own vehicle.', split_comma'#1 galaxy saved from weevils by lone pilot. all thankful.|president and vice president arrested accused of hoarding carrots and broccoli.|galaxy looking forward to eating better again.|colonists wanted for mission to former weevil system.|sloths, snails and tortoise alliance begin discussions about weevil sightings.|cats still refusing to commit on entering #1 galactic union- are they in or out?', },x=-128,item=0}, {who=0,system=0,station=0,x=-64}, -- M dr_start, -- D {}, -- U split'\fbharn\-enless,\febit of a softy,\fca little harn\-enful,\f6son\-enetin\-enes dangerful,\f9a v\-evee spot deadly,\fabit of a predator,\fbbug hunter,\f7death incarnate,\f8the extern\-eninator', split&quot;got any carrots?|searching for some broccoli\nyou got any?|have you heard there\nare weevils invading?|i don't believe in weevils.|i heard there's a planet\nwith naked apes on it\nwho are obsessed with\na thing called 'money'\n- crazy huh?|i'm heading for the \n#1|weevils are\na government hoax|how are you liking\n#2?|my father was called\n#3|make #4\ngreat again!,#2 should be\nan independent system\noutside the\n galactic union|weevils are a government\ntactic to distract us from\nthe real issues|if #2\nwere independent we'd\nnot have this weevil\nproblem|i'm sure our government\nwill sort everything out\nsoon|aunt dahlia's recipes\nare really good\nbut i miss carrots|i think i saw a\nweevil yesterday|do you have any\nbroccoli captain\n#3?|i hope there aren't any\nweevils raiding around\nthe #1,i still haven't found any carrots|what do i have to do\nto find broccoli in\nthis galaxy?|the weevils are just the\ntip of the iceberg\nmark my words|#3 is\na nice name|i'm #2 born and bred!|the #4\nunion needs us more\nthan we need them!,h-have you s-seen\nany weevils\nround here?\nthe news scares me|that's a nice ship you\nhave captain #3|i miss broccoli more\nthan carrots but i\nstill miss carrots|the government has no\nidea what it's doing|i trust our president\nto fix this weevil\nproblem,my brother still refuses\nto believe in weevils|psst - i know\nwhere you can\nget carrots still|what kind of weevils\nhave you seen\ncaptain #3?|don't let the government\nvaccinate you against\nweevil infection\nthey'll put a chip\nin you!|there are some really nasty\nweevils out there now|i told my parents not to\ntravel anymore|i hope the #1\nis still there,i was told that the\nweevils took over an entire\nsystem as a base|this species of weevil\nis supposed to be led\nby a huge queen|#4 has\nno regard for the rights\nof #2!|when i get to\nthe #1 i\nhope they have\nbroccoli|have you seen the\npresident recently?|i heard that the\n#4 fleet has\nrun away from\nthe weevils!|i don't know what i\nwouldn't do for\na carrot right now,hey captain #3 -\nyou're the best!|thanks for saving the\n#4 galaxy|i still can't find\nany broccoli|it's a lot quieter in \n#2 now|i heard they found carrots\nat the #1|#2 would\nhave coped with the weevils\nwithout the interference\nof #4|are you the real\ncaptain #3?&quot;, 2, -- g_diff split'\fb easy,\fcnorn\-enal,\f8 hard', --g_diffs {},{}, unpack_split'0,0,0,1000,10000,10240,2,1024,0,1,0,0,0,0,0,2307,1,1,23,0,5' -- other globals</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p></div></div></div><br /> This is the most extreme example I have and hopefully ever will commit again...</p> <h1>Functions</h1> <h2>Arguments</h2> <p>Rely on default arguments and persistent states (like the draw colour) where you can e.g.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>print(a,0,23,10,7) print(b,0,23,10,7)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>could be</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>print(a,0,23,10,7) print(b,0,23,10)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Also:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>camera(0,0)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>vs</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>camera()</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The explicit arguments cost every time.</p> <h3>More can be better</h3> <p>As well as passing fewer arguments to a function, you can also pass more - lua doesn't choke. How can <em>more</em> arguments save tokens?<br /> If you are calling functions that you've assigned to variables that you can call with the same code, but require different numbers of arguments then just pass all the arguments every time e.g. draw methods that change between different entities in your game might sometimes need colours or not.<br /> Also remember that a table index that hasn't been defined is treated as nil. So passing tab.foo to a function when tab.foo has never been assigned is just the same as passing nil.<br /> As long as the code in the functions doesn't choke on nil values for those arguments then you don't need any clever control flow to try and get the number of arguments &quot;right&quot;.</p> <p>Example:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function make_ent(dr,x,y,c1,c2) return {dr=dr,x=x,y=y,c1=c1,c2=c2} end function draw_a(x,y,c1,c2) -- some drawing code here end function draw_b(x,y) -- some drawing code here end ents={make_ent(draw_a,0,0,8,9),make_ent(draw_b,0,20,6,7),make_ent(draw_a,20,49)} for ent in all(ents) do ent.dr(ent.x,ent.y,ent.c1,ent.c2) end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Taking this example further, I might look to use unpack_split on the multiple literal values in the make_ent calls. I'd then wonder whether I could find a way of describing all the entities in a single string that I could process with split and unpack - there's likely to be more than three entities in my game after all.</p> <p>For example, currently I'm writing a game that unpacks all the platforms, walls, floors, monsters, goodies etc. via the same function per collection (now I'm wondering whether I could do all collections together...). The number of bits of data per each entity is the first number followed by values for each entity. i.e.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- each spid has 3 values x,y position and y vector g_spids=unpack_raw_data'3,550,160,1,540,40,1,200,70,1,300,90,1,800,25,1,864,200,-1'</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>I suggest using an editor to produce strings like this rather than try to write the data by hand. The PICO-8 printh function is v handy for getting data out of an editor into a file or to the console you run PICO-8 inside. You do run PICO-8 from the command line, right? :)</p> <p>Note: a lot of characters are wasted doing it this way e.g. every ','. Hex values would be more compact as well. If you can keep all values within a byte range then encoding them as raw characters works very well too and Zep has even given us the magic function to decode them here: <a href="https://www.lexaloffle.com/bbs/?tid=38692">https://www.lexaloffle.com/bbs/?tid=38692</a>.<br /> I use this for image data and sfx data (hope to write about both soon).</p> <p>Thinking about functions again, remember that in lua the following are equivalent:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>tab['a'] tab.a</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>So that by putting the draw functions in the example further up into a table you could specify which function to use via an element in a data string. Something like:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function make_ent(dr,x,y,c1,c2) return {dr=draw_funcs[dr],x=x,y=y,c1=c1,c2=c2} end ... for ent in all(ents) do ent.dr(x,y,c1,c2) end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Or even at call time:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>for ent in all(ents) do draw_funcs[ent.dr](x,y,c1,c2) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(I suspect that would be slower - maybe easier to debug though)</p> <p>If your data parsing function is clever enough then you probably don't need a separate constructor function like that at all.<br /> Along those lines, say if every entity has position (x,y) and most have velocities (vx,vy) but one type only has a colour and no velocity then it's nice to code it with a proper index name &quot;ent.col&quot;, but if it means writing separate construction code then consider just using ent.vy and a comment(or at least adding something like local col=ent.vy when you need it).</p> <p>I haven't done this, but it may be even more efficient to dispense with named elements in your tables so you could do:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>for ent in all(ents) do ent[1](unpack(ent)) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"><br /> This works, for example:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>ent=split'1,e,1,2,8' cls() dr_funcs={ function(d,...) print(...) end } dr_funcs[tonum(ent[1])](unpack(ent))</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p></div></div></div></p> <p>todo: random numbers, number indices vs named indices, caching table values in local variables (fewer tokens and faster too!)</p> <h3>Bonus: unpacking into memory</h3> <p>I'm going to add more to this post, but for now I'll end with this:</p> <p>Have a table of values e.g. an image stored as bytes? Want to dump it into memory or onto the PICO-8 screen easily? You can as of the recent PICO-8 updates:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>poke(0x6000,unpack(data))</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>6 tokens<br /> Bang - straight onto the screen. Poke4 is even quicker and the same number of tokens if you have your image data nicely packed into table values. I use this for 'extra' sprite sheets, for instance.<br /> Be warned though: down this road lies the terror of the compressed size limit...</p> <p>(I tried this just now vs memcpy(0,0x8000,0x2000) and it's much quicker - not v scientifically though so YMMV)</p> https://www.lexaloffle.com/bbs/?tid=45114 https://www.lexaloffle.com/bbs/?tid=45114 Fri, 22 Oct 2021 21:38:55 UTC Printing Outlined Text <p>Early on in playing around with PICO-8 I wrote a function to print text with a black outline.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function prt_out(s,x,y,c) print(s,x-1,y,0) print(s,x+1,y) print(s,x,y-1) print(s,x,y+1) print(s,x,y,c) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>I imagine a lot of people have also done this and I can't be the only person who found it a bit clumsy and, near the end of a project when casting about for tokens, wondered if those five very similar print calls couldn't be reduced.</p> <p>Nowadays we have P8SCII so I thought I'd have a look. Here are some candidates I've written with their token counts and times from my crude testing:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function p1(s,x,y,c) -- 42 tokens, 5.6 seconds ?'\f0\-f'..s..'\^g\-h'..s..'\^g\|f'..s..'\^g\|h'..s..'\^g\f'..chr(c+(c&gt;9 and 87 or 48))..s,x,y end function p2(s,x,y,c) -- 26 tokens, 6.2667 seconds for i in all(split'\f0\-f,\-h,\|f,\|h') do ?i..s,x,y end ?s,x,y,c end function p3(s,x,y,c) -- 38 tokens, 5.6667 seconds ?'\f0\-f'..s..'\^g\-h'..s..'\^g\|f'..s..'\^g\|h'..s..'\^g\f'..sub(tostr(c,1),6,6)..s,x,y end function p4(s,x,y,c) -- 30 tokens, 5.7 seconds ?'\f0\-f'..s..'\^g\-h'..s..'\^g\|f'..s..'\^g\|h'..s,x,y ?s,x,y,c end function p5(s,x,y,c) -- 42 tokens, 6.1 seconds print(s,x-1,y,0) print(s,x+1,y) print(s,x,y-1) print(s,x,y+1) print(s,x,y,c) end function p6(s,x,y,c) -- 29 tokens, 6.2 seconds for _,i in pairs{'\f0\-f','\-h','\|f','\|h'} do ?i..s,x,y end ?s,x,y,c end function p7(s,x,y,c) -- 37 tokens, 6.2667 seconds for i in all{'\f0\-f','\-h','\|f','\|h','\f'..chr(c+(c&gt;9 and 87 or 48))} do ?i..s,x,y end end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>'?' vs print makes no difference to performance, but does save characters and 1 token each use.</p> <p>I was rather surprised that p2 uses so few tokens and isn't <em>that</em> slow. Also that p1 is actually the fastest (but only just).</p> <p>I usually find that tokens are more precious to me than a tiny bit of performance so I'm likely to use p2 above. p4 is pretty cheap at 30 tokens and faster than the naive approach so perhaps it's an overall winner (so far).</p> <p>I'm very interested to know if anyone has a better way(?)</p> <h2>v1 edit:</h2> <ul> <li>freds72's suggestion is p6. 3 more tokens for .0667 seconds faster. Using pairs() instead of all() causes half of that saving.<br /> I thought removing the split might make more difference than that, but now I feel a bit better about having split all over my game code to save tokens(!)</li> <li>I removed the unnecessary '\^g' (go home) parts from the P8SCII snippets where appropriate. This saves some characters and performance (but also somehow saved the odd token and I'm not sure how).</li> </ul> <p> <table><tr><td> <a href="/bbs/?pid=98796#p"> <img src="/bbs/thumbs/pico8_drakeblue_prt_out-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=98796#p"> drakeblue_prt_out</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=98796#p"> [Click to Play]</a> </td></tr></table> </p> <h3>Bonus</h3> <p>Specify the colour of the outline:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function p4bonus(s,x,y,c,o) -- 34 tokens, 5.7 seconds color(o) ?'\-f'..s..'\^g\-h'..s..'\^g\|f'..s..'\^g\|h'..s,x,y ?s,x,y,c end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(Please use any of these functions if you want)</p> https://www.lexaloffle.com/bbs/?tid=45020 https://www.lexaloffle.com/bbs/?tid=45020 Sun, 17 Oct 2021 18:19:19 UTC Reflection <p> <table><tr><td> <a href="/bbs/?pid=98701#p"> <img src="/bbs/thumbs/pico8_db_reflection-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=98701#p"> db_reflection</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=98701#p"> [Click to Play]</a> </td></tr></table> <br /> A simple demo of a reflection.</p> <p>Press X to enable/disable the reflection effect.<br /> Press Z to enable/disable the ripple effect.</p> <p>Use up/down to move the view up and down i.e. change the amount of reflection on the screen.</p> <p>Uses the extra palette to dim the portion of the screen where the reflection will be.<br /> Draws everything else like normal above the reflection surface.<br /> 'memcopy's to the lines below the reflection surface, starting with the line immediately above it.<br /> Adding an offset with some sin() calls moves each line a bit to allow the ripple effect. Downside is a little bit of mess at the edges.</p> <p>[edit] Minor bug fix to make ripple effect constant with distance from the shore.</p> https://www.lexaloffle.com/bbs/?tid=44997 https://www.lexaloffle.com/bbs/?tid=44997 Fri, 15 Oct 2021 16:09:44 UTC Fireworks <p>Fireworks<br /> <table><tr><td> <a href="/bbs/?pid=90763#p"> <img src="/bbs/thumbs/pico8_drakeblue_fireworks-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=90763#p"> drakeblue_fireworks</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=90763#p"> [Click to Play]</a> </td></tr></table> </p> <p>Some fairly simple particle fireworks just for fun.<br /> Press X to switch the screen effect on/off. For more about that see here: <a href="https://www.lexaloffle.com/bbs/?tid=41149">https://www.lexaloffle.com/bbs/?tid=41149</a></p> <p>Every sixth of a second, 50-100 Particles are emitted at a random point on the screen with random angle/velocity determined by a tiny bit of trig. They're given colours in the top half of the PICO-8 palette (7+) and as the particles get old the colour changes according to the same mapping that the screen fade effect uses to a darker colour.<br /> If they run out of life or become black then the particles are deleted.<br /> There are two possible update functions for each particle - one with a wiggle :)</p> <p>-- update: tidied code a bit, updated fade effect.</p> <img style="" border=0 src="/media/47206/fireworks p8_0.gif" alt="" /> https://www.lexaloffle.com/bbs/?tid=42528 https://www.lexaloffle.com/bbs/?tid=42528 Sun, 18 Apr 2021 14:02:59 UTC Making PICO Space <h1>Making PICO Space</h1> <p> <table><tr><td> <a href="/bbs/?pid=89915#p"> <img src="/bbs/thumbs/pico8_drakeblue_picospace-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=89915#p"> drakeblue_picospace</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=89915#p"> [Click to Play]</a> </td></tr></table> </p> <p>This is a rambling description of some of what went into making <a href="https://www.lexaloffle.com/bbs/?tid=42279">PICO Space</a>. I've tried to write it for most readers to follow - there's some basic stuff and nothing very advanced. Hopefully it's not too dull and might help someone.</p> <img style="" border=0 src="/media/47206/space_77.gif" alt="" /> <h2>When You Wish Upon a Starfield</h2> <p>Coming up to Christmas of 2020 I had been spending most of my dev time trying to squeeze image data into PICO-8 to make a Dungeon Master clone (I promise I will return to this at some point). I'd got a bit tired of writing compression and encoding routines and feeling like I was fighting PICO-8 rather than playing nicely with it. I'd seen some other nice star-fields and particles in other peoples' games and wondered how much it would take to do my own.</p> <p>I'd also read about the CAMERA function and suspected that would help - using CAMERA to transform the &quot;view window&quot; once instead of transforming the positions of every single particle many times seemed like it'd be a big win in terms of performance.<br /> I knocked up the following while the girlfriend was watching a Christmas movie to try it out. Ironically, the stars in the final game don't benefit from the CAMERA function at all - although the other particles and everything else do.</p> <p> <table><tr><td> <a href="/bbs/?pid=90118#p"> <img src="/bbs/thumbs/pico8_drakeblue_camerastars-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=90118#p"> drakeblue_camerastars</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=90118#p"> [Click to Play]</a> </td></tr></table> </p> <p>There's not a lot to it: use directions to &quot;fly&quot; the red line around (there's nothing there, but the star field). But this is the basis of how the ship flies in PICO Space.</p> <p>I wrote a post about the stars and fade effect here: <a href="https://www.lexaloffle.com/bbs/?tid=41149">https://www.lexaloffle.com/bbs/?tid=41149</a><br /> <table><tr><td> <a href="/bbs/?pid=86396#p"> <img src="/bbs/thumbs/pico8_fading_stars-5.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=86396#p"> fading_stars</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=86396#p"> [Click to Play]</a> </td></tr></table> </p> <p>I considered a rotate and thrust method, like in games like Thrust, Oids etc. but decided to keep it simpler, friendlier to those who didn't grow up in the 80s and allow the game to be more dynamic. Left, right and thrust would have saved a precious PICO-8 button though...</p> <p>In the final version, there's a constant deceleration added to the velocity components of the ship (which gets wiped out if you hold down the controls) - and a very low minimum velocity. Why?</p> <h2>Not Just a Triangle; Not Even a Triangle</h2> <p>The ship (and the NPC ships) are all drawn in the game using a combination of lines and a sprite to cover the hole in the middle (yes, really - I had some triangle drawing code sat in the p8 file for weeks without ever actually using it in the end so it got cut). The vertices used for the lines are calculated from a normalised vector of the ship's velocity. If the velocity gets too close to zero then this calculation, the vertex calculations and the lines don't come up with anything sensible and the ship doesn't draw correctly.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>----------------------------------------------------------------------------------------- -- draws the player or an npc ship function draw_ship(s) ship_pal(s) -- calc some vertices based on current heading angle -- 0 -- (0) -- 2 1 local z,an=s.z&lt;1 and -1 or 1,s.an local s0,s1,s2,c0,c1,c2=sin(an)*z,sin(an-0.15)*z,sin(an+0.15)*z,cos(an)*z,cos(an-0.15)*z,cos(an+0.15)*z local svx0,svy0,svx1,svy1,svx2,svy2=3.5*c0,3.5*s0,-3.5*c1,-3.5*s1,-3.5*c2,-3.5*s2 line(svx0*1.2,svy0*1.2,svx1*1.2,svy1*1.2,2) line(svx0*1.2,svy0*1.2,svx2*1.2,svy2*1.2) line(svx1,svy1,svx2,svy2) line(svx0,svy0,svx1,svy1,8) line(svx0,svy0,svx2,svy2) line(0,0,svx1,svy1) line(0,0,svx2,svy2) line(0,0,svx0,svy0) spr(unpack_split'0,-4,-4') -- cockpit reset_dr_pal() end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>ship_pal sets up the correct colours for whatever ship is being drawn - there's a pair of values for every brighter colour apart from the blue used for the cockpit.</p> <p>The z variable deals with the &quot;flip&quot; ability that the ship has so you can face backwards - otherwise, while the ship does have some inertia it will always be drawn to point in the direction it's moving.</p> <p>I'll explain more about &quot;unpack_split&quot; in another post.</p> <p>Here's the ship without the cockpit sprite:</p> <img style="" border=0 src="/media/47206/space_72.gif" alt="" /> <p>reset_dr_pal is a function that acts like a call to pal with no arguments, but doesn't affect the screen palette. I've used it for a few projects now:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function reset_dr_pal() poke4(0x5f00,0x0302.0110,0x0706.0504,0x0b0a.0908,0x0f0e.0d0c) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The latest PICO-8 letting consecutive values be multiple pokes at a time has let me optimise this so it's a bit opaque even to me. IIRC it dumps the equivalent of 0,1,2,...,15 into the correct part of PICO-8's memory to reset the draw palette and whatever magic needs to be done for palt too(?), but doesn't hit the screen palette range of memory.</p> <p>Feel free to lift this for your own code if you think it'll be useful - no warranty expressed or implied ;)</p> <p>I tweaked the ship drawing code a few times, but it never varied much. Once I had a ship flying about I needed somewhere for it fly to so I made a &quot;planets&quot; table that was populated with random coordinates, drew a circular planet sprite and hit go. That's gone now - it was handy to have as a placeholder, but I don't miss it.</p> <h2>Start of a Solar System</h2> <p>Once I had planets it made sense to me to add a sun/star, but I wanted it to be bigger than the planets. I'd already used 64x64 of the sprite sheet with the planet sprite so I wondered what I could do with PICO-8's circfill command.</p> <p>It turns out that circ and circfill let you draw pretty large circles for not a great deal of perf cost. I tried various sizes and settled on an 800 pixel radius circle for the sun with some extra circles around it. One is a border, the others are there just because I like how they look. My &quot;game design&quot; excuse is that they give some warning to the player that they're about to fly into a star - not v healthy for their ship.</p> <img style="" border=0 src="/media/47206/space_70.gif" alt="" /> <p>I have another cart that draws a partial circle within another circle to show the sun on the scanner, but the token count was too much. In the end, the sun on the scanner is drawn by generating lots of points then checking if they are within both the circle of the sun and the circle of the scanner; then drawing a circle of radius 1.</p> <p>Originally I had yet another circle for the edge of each system - but as the systems got busier the performance cost was just too high so I needed something a bit more &quot;sophisticated&quot;. I noticed that the edge circle was so large that it never looked like anything else but a straight line on the little PICO-8 screen so in the game I do a little bit of maths to work out two intersection points with the edge circle and draw a line between them i.e. the edge circle segment is approximated with a line.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>--edge of system if g_dist_to_sun&gt;g_edge-23 then -- approximate with drawing tangent line at angle through ship's coordinates -- since ship is so far from centre and edge circle is so large -- edge is a circle around 0 -- get angle to ship local an,ed=atan2(S.x,S.y),g_edge+rnd'16' -- get tangent angle at 90deg and coords of point on edge (with some jitter) local an2,ca,sa=an-0.25,cos(an)*ed,sin(an)*ed -- get vector of line using tangent angle local ca2,sa2=cos(an2)&lt;&lt;7,sin(an2)&lt;&lt;7 line(ca-ca2,sa-sa2,ca+ca2,sa+sa2,p%8+8) end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <img style="" border=0 src="/media/47206/space_74.gif" alt="" /> <p>I use g_dist_to_sun to conditionally draw the sun when needed as well.</p> <p>Having a circular edge seemed like a nicer way to stop the ship flying too far out of the game than just clamping to a rectangle or wrapping the coordinates. I had a really fancy bit of code that would turn the ship around from anywhere outside the system and force it back. In the end just adding a vector pointing towards the centre of the system to the ship's velocity is what makes it behave like a stuck blue bottle behind glass in the game.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre> g_dist_to_sun=dist_trig(S,g_sys.sun) if g_dist_to_sun&gt;g_edge then local avx,avy=get_dir(S,g_sys.sun) vx+=avx vy+=avy end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Trigonometry for Distances</h2> <p>(As any fule kno) the distance between a point A and B is the square root of the sum of the squares of the coordinate distances i.e. d = sqrt(dx<em>dx+dy</em>dy) -- for 2D</p> <p>Except not in my game.</p> <p>In a fit of madness I decided to make the systems pretty large, 10240 pixels in radius, in fact. PICO-8 numbers are a 16-bit fixed point type with a range of -32768.0 to 32767.9999847412109375 (0x8000. 0000 to 0x7fff). Which means I was fine until I needed to calculate a large-ish distance and had to square numbers over 1000 e.g.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>dist({0,0},{9000,8000}) = sqrt(9000*9000 + 8000*8000) = sqrt(81000000 + 64000000)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Um...</p> <p>Weirdly, I got a really long way into coding before this actually became a problem and I'm not quite sure how that happened - especially since I was expecting it all along, I'm no stranger to the limitations of number types or even to fixed point floats.</p> <p>One method I tried to get round this was to divide every value (bit shift in fact) before the squaring operation and then shift back afterwards. I'd lose precision, but in theory it'd work fine i.e. something like:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>dist = sqrt( (dx&gt;&gt;4)*(dx&gt;&gt;4)+(dy&gt;&gt;4)*(dy&gt;&gt;4) )&lt;&lt;4</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Most of the time I'd only needed the shifted squared value. But I had real trouble getting it to work well - possibly because of other code around it. And sometimes I wanted the true distance (with the sqrt) anyway.</p> <p>I'd been doing some experimentation with the SIN and COS functions and I'd noticed that they're very fast on PICO-8 and I wondered about whether this might be another solution.</p> <p>A bit of trig later and I had a candidate:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- distance with trig -- to avoid large numbers -- not v accurate, but seems good enough. -- also seems v fast on pico-8 function dist_trig(a,b) local x,y=abs(b.x-a.x),abs(b.y-a.y) if x&lt;y then x,y=y,x end -- accuracy goes down massively if x is much smaller than y so swap them :) return x/sin(atan2(y,x)) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>I discovered the accuracy problem mentioned in the code a bit later - it manifested as the ship spontaneously diving into the sun if you flew too close to the top or bottom of it - and only those two points. The code to stop the ship escaping the edge of the system was firing and pushing the ship into the centre of the system because the distance calculation was so bad it thought the ship was at the edge not right by the sun!</p> <p>Anyway, this function gets used all over the place now and was favourably comparable in accuracy and speed to any of the shifted distance functions that I tried.</p> <h2>Galaxy Generation</h2> <p>Of course, the more sensible solution would probably have been to make the star systems smaller and &quot;zoom&quot; the coordinates only for drawing, but I'd already done most of the work on galaxy creation and drawing and didn't really want to change it too much. I think I actually tried it for 30 minutes, made a mess and then gave up.</p> <p>When you choose a new game or load from a saved game in PICO Space it generates the whole galaxy from an integer seed (your captain's name is a different value; otherwise they couldn't travel to other galaxies...).</p> <p>The stars are all generated from the galaxy seed plus a fraction part e.g. the fourth star has something like id=galaxy_id+4*0.0001. This means there are potentially 65535 galaxies (I think, or at least 32767) with every system having a unique id/seed &quot;in the gaps&quot;.</p> <p>Apart from star number 1 which is always at (0,0), the stars are given random positions within a fixed distance from that star with the condition that they can't be too close to an already existing star. This is v fast.</p> <p>Then the code links the galaxies with wyrmholes (called gates in the code). First it makes a minimum spanning tree with wyrmholes:</p> <ul> <li>find the star with minimum distance from star 1</li> <li>add wyrmholes to link the two</li> <li>add the new star to star 1 in a &quot;found&quot; set</li> <li>find the closest star to any star in that set</li> <li>link with wyrmholes</li> <li>repeat last 3 steps until every star is in the &quot;found&quot; set</li> </ul> <p>This way I know that every system is connected to the galaxy as a whole. Without this some systems aren't reachable (I had considered having a jump drive upgrade that let you jump between groups of stars - maybe next time).</p> <p>Unfortunately my algorithm to calculate the minimal spanning tree gets v slow after relatively few iterations (checking the closest star in an n-size set of stars has a pretty bad O value) and acts as a mechanical limit to how big the galaxies can get.</p> <p>I'd be more worried about it, but for two things:</p> <ol> <li>The loading view covers it well. It looks like the stars are being generated, but it's actually showing the stars being added to the minimum spanning set.</li> <li>It's fast enough that even with 70 stars it's not that slow and I think 70 stars is probably enough.</li> </ol> <p>--controversial?--I've noticed in a lot of procedurally generated games there's a whole load of repetitious content where there doesn't really need to be - it doesn't add much to the game and feels a bit like it's there just because the developers could. Now PICO Space is still pretty guilty of this - there's a lot of space in PICO Space and 70 systems is probably still way more than most players will ever visit. The systems don't have that much variety - I really wanted to put in more and kinda of heart-breakingly PICO-8 is easily <em>fast</em> enough to allow it. But there's not much cart space and I just couldn't find the tokens. There were a lot of things I would have added without the token limit and even some stuff I had to cut before release. I never found myself wanting to add more star systems. In fact, for a lot of dev time I reduced the number to make testing faster.--/controversial--</p> <p>Anyway, long story short: I didn't waste any more time (or tokens) optimising this, instead I slapped in a logo and a few star spr calls and pretended it was a deliberately designed intro sequence...</p> <p>Once that's done, there are a few iterations after the spanning tree search looking for short distances between stars and adding more gates between them so that there are &quot;loops&quot; and it's a bit easier to get about. This is pretty fast too.</p> <img style="" border=0 src="/media/47206/space_76.gif" alt="" /> <h2>Generating Systems</h2> <p>Then the systems themselves are fleshed out. Originally I generated each system in the galaxy only when the player entered them. In fact, all I had was the current system and some wyrmholes in it. When the player entered a wyrmhole I took the seed value associated with it and generated the new system. I even added a wyrmhole back to the previous system using its seed to give the illusion of persistence. For the galaxy map I was going to run this generation on the fly when it was opened to a certain depth of wyrmholes and that way I'd have a near to infinite galaxy and tiny memory footprint!</p> <p>Typing it out now it still seems like it might have worked, especially as I know the scope of what's in the game. At the time though, I ditched that idea since I didn't. The final straw was wanting to put &quot;missions&quot; into the game.</p> <p>Each system has wyrmholes and planets which also may have space stations orbiting them. The wyrmholes, only really have a position, a destination id and a draw function. They are called wyrmholes because I was hoping to have &quot;space wyrms&quot; in the game. Sadly, that never happened.</p> <h3>Planets</h3> <p>Planets have radii and colours and are added in distance &quot;slots&quot; (with the wyrmholes) radiating out from the sun - this way there shouldn't be any collisions between them, even as the planets orbit around the star. Yep, the planets do orbit in the game, but their positions only update when entering a system. I had them update along with everything else for a long time though.</p> <p>As mentioned elsewhere in this post, the scale of each system is quite large. The planets orbit in circles determined by sine and cosine functions combined with their distance from the star (I balked at setting up stable systems with realistic gravity calculations if only because I'd disappeared down enough wyrmholes already). Unfortunately, the precision of these functions isn't high enough to allow smooth movement when any distance from the sun. It caused the planets to &quot;jump&quot; between positions on their orbit. Unperturbed I wrote a routine to interpolate between the imprecise positions so that the planets would still orbit smoothly. It worked really well and I was sad to have to cut it to regain the tokens it needed.</p> <p>I was able to leave the scribbly planetary rings in place though, which are drawn by generating a bunch of vertices using sine and cosine values (with random jitter) and drawing lines between pairs of them. Draw the back half of a ring first, draw the planet, then draw the front half of the ring.</p> <p>Like the planet interpolation, I designed them in a separate test cart first:</p> <p> <table><tr><td> <a href="/bbs/?pid=90118#p"> <img src="/bbs/thumbs/pico8_drakeblue_rings-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=90118#p"> drakeblue_rings</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=90118#p"> [Click to Play]</a> </td></tr></table> </p> <p>The code in the game is very similar. Knocking up little test carts is nice in PICO-8 since it's v lightweight to get going. Doing this also means less messing up of existing code, especially if you change your mind and it means less flying about trying to find the thing you want to test.</p> <h3>Space Stations</h3> <p>The space stations do orbit as you fly, around the planets. A planet has a station entry in its table so there's only one per planet (early in dev I had up to 4!) and the space station positions get updated with everything else that updates. When you're docked the ship has to match this (that was a fun bug).</p> <p>The space stations have three different sprites, a few circles and a pal call in their draw function to provide some cosmetic variety. I had written a little cart which would allow me to specify shapes, sprites and map commands in a string that was interpreted at runtime to give many more looks for them, but tokens and performance stopped me using that. And I hit the compressed size limit quite badly too.</p> <p>At one time there was a ship's garage with mechanic NPCs in every station but alas tokens...</p> <h2>Missions</h2> <p>(kinda)</p> <img style="" border=0 src="/media/47206/21_space_57.gif" alt="" /> <p>I wanted to add a whole different variety of these, but eventually I only made the passengers on the noticeboards at the stations - the simplest missions I could think of. They're even more basic than fetch quests (find something <em>and</em> bring it back - sounds complicated!) or even deliveries (plausibly you only have room for one passenger in your small ship so I only needed to track one mission at a time). I ran out of tokens before I could attempt adding any more types.</p> <p>To make the passenger missions work I needed to have some knowledge of not just the name of the destination system, but also of the objects in the system; specifically the space stations. I'd hoped to have docks on planets, but, again, the token limit got the better of me.</p> <p>It was so much easier to have the destination systems pre-created and in memory for this. PICO-8 has a generous 2MB for such data (my first computer had 64KB and David Braben and Ian Bell made do with a fraction of that). PICO-Space only ends up using about half of that at any time (when it's working correctly).</p> <p>The game takes a seed of the current space station id and the progress that the player has made through the game and uses that to generate a number of notices with destinations and a seed for the animal wanting a ride. That way, if you return to the notice board it keeps the same notices, at least until you complete a mission.</p> <p>When you finish enough journeys a progress global is increased, an upgrade is awarded, different news &amp; NPC messages are unlocked and more dangerous weevils may appear. There's an upper limit to how many journeys are needed for each progress point (four I think) so every player should progress reasonably quickly.</p> <h2>Silly Names</h2> <p>Nonsense word generators are something I've written a few times in the past. They're very effective (and entertaining) for something so easy to do. If you've never written one I highly recommend it, especially for newer programmers.</p> <p>There is a single list of syllables and a single function that generates all the names in PICO Space. If I had more space/tokens then having different syllable sets etc. per species or system or something might have been fun, but I never felt like this was a weak part of the game and garnered an embarrassingly large amount of amusement out of some of the silly things it came out with.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>------------------------------------------------------------------------------------------ -- generate some wacky random names function gen_name(s) stash_n_set_seed(s) local n,nm=rnd_spl_str&quot;1|2|2|2|3|3|3&quot;,'' for i=1,n do if i&gt;1 and rnd(15)&lt;1 then nm..=' ' end nm..=rnd(g_syls) end unstash_seed() return nm end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The gist of this is:</p> <ul> <li>choose length for the name in number of syllables</li> <li>for each syllable up to thate length choose a syllable string and append it</li> <li>occasionally append a space instead of a syllable</li> </ul> <p>The stash_n_set_seed function is my hack to get around the trials and tribble-ations of working with a random number generator for procedural generation (as opposed to a noise function). See below for more about this.</p> <p>Here's the syllables:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>split&quot;ca,bal,da,gar,non\-en,pol,der,arp,bun,duc,kit,poo,v\-evee,zir,buf,v\-evil,xan,frak,ing,out,re,far,do,tel,tri,cry,quack,er,dog,pup,sno,ger,bil,pa,n\-ena,jan\-en,es,on&quot;,--g_syls</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>For more serious names, don't put in such silly syllables e.g. poo.</p> <img style="" border=0 src="/media/47206/space_66.gif" alt="" /> <h2>Ms and Ws</h2> <p>The eagle eyed amongst you may have noticed that PICO Space has &quot;wide&quot; 5x5 pixel M and W letters instead of the usual 5x3 characters that PICO-8 has by default. My other games, e.g. P8C-BUN have similar wide Ms and Ws too. In those games, I have a custom print function that iterates through whatever string is to be printed and when it finds an M or W it replaces it with a sprite that has the wide version of the letter. I added this after I got some negative feedback about the legibility of the text in a game.</p> <p>Originally PICO Space used the same function, but I found it was a bit of a performance problem. PICO-8 has a much more &quot;spiky&quot; processing time per frame than my other games have had.</p> <p>Fortunately, zep's addition of P8SCII in the newer version of PICO-8 came at exactly the right moment and allowed me to replace my routine with these magic codes:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>m=&gt; n\-en [print an n then shift the cursor back 2 pixels (\-e) and print another n] w=&gt; v\-ev [u\-eu looks okay too]</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>As long as a find/replace is done for those characters in a string to be printed then it &quot;just works&quot; and I was able to ditch my custom print routine at last. This can be done &quot;offline&quot; even. The only tricky part was trying to centre text when the width was no longer as predictable - I do have a mostly working solution for that. Ask me if you're interested.</p> <h2>Taming RND</h2> <p>PICO-8 has no noise function, but it does have RND and a seed set function SRAND. I considered writing a noise function, but I suspected I'd want the tokens for something else and I was concerned about performance. I'd already used RND for the first hacky progress in the game when I thought about this so I gave up on noise and set up a function that saved the current random number (or at least whatever RND returned at that moment) and called SRAND with a value I'd passed to it. Then I was careful with the order I called RND in and did a lot of testing to make sure that I got consistent or random results as appropriate.</p> <p>For a particular seed, RND always returns the same sequence of subsequent results so, for instance, setting the seed before choosing portrait sprites and generating a bunch of names using RND means you'll always get the same output. That's why there's always the same animal minding each station and the same notices each time you look on a station's noticeboard (at least until you ferry another passenger). I'd restore a &quot;random&quot; seed after using RND in this way so that, for example, the NPC generation stayed unpredictable.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- set seed and store a random number for later function stash_n_set_seed(seed) g_old_seed=rnd() srand(seed) end -- restore &quot;randomness&quot; function unstash_seed() srand(g_old_seed) end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This works pretty well all considered and I never felt I was having performance problems from it. I call the time function for the galaxy seed and pilot id just to mix it up even more.</p> <h2>Animals</h2> <p>I needed characters for the game and I considered identikit faces like Elite 2 uses for a bit. In the end, I drew some animals as placeholders and then never looked back.</p> <p>Animals feature in my games. Get over it.</p> <p>I wanted the portraits to move so initially I was going to add animation frames, but horizontally flipping was easier and meant I could have more unique pictures. I figured it was &quot;good enough&quot;.<br /> <table><tr><td width=128> <img src="https://www.lexaloffle.com/bbs/gfxc/47206_0.png" width=128 height=128> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_47206_0"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/47206_0.txt", function (retdata){ var el = document.getElementById("gfxcode_47206_0"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [32x32]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_47206_0" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> </p> <p>There are 59 animals in total.</p> <h2>News and NPCs</h2> <p>The Beeb News was my first attempt to communicate some story in the game and add a bit of narrative colour (alongside the colour colour). The news stories develop as the player progresses in the game - there's a different set after each upgrade is achieved. I used a <em>very</em> basic template filling function to generate a bit of customisation for each game - e.g. the galaxy name and the president's name change depending on which galaxy you're in.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>------------------------------------------------------------------------------------------ -- substitutes values (#n) into a string for the corresponding entry in data (data[n]) function template_fill(t,data) local i,out=1,'' while i&lt;=#t do local c=sub(t,i,i) if c=='#' then i+=1 out..=data[tonum(sub(t,i,i))] elseif c=='m' then out..='n\-en' elseif c=='w' then out..='v\-ev' else out..=c end i+=1 end return out end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>You'll notice the M and W substitutions in this - in the last week of development I had to add this to reduce the size of the strings used for the news and NPC chat in order to fit the game under PICO-8's compressed size limit. Fortunately, it works very well and turned out to be quick enough.</p> <p>The news is drawn using the same scrolling message system that is used for the upgrades and notice board, just with different colour parameters.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>---------------------------------------------------------------------- -- draws a bar of scrolling text function draw_scroller(scroller,y,x,c,bc) clip(x,y,128,y+6) rectfill(x,y,128,y+6,bc) print(scroller.message,x-scroller.x,y+1,c) clip() scroller.x+=1 if scroller.x-x&gt;scroller.len then scroller.x=-64 return 1 end end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>NPCs</h2> <p>The other attempt at story telling comes from the NPC ships. These will send you random messages when they're on-screen. Like the news, the template function adds a bit of customisation e.g. for the current system and there are different sets of messages for each stage of progress in the game.</p> <p>The NPCs are (obviously) drawn in the same way as the player ship, but on top of basic attributes like position, velocity, colour etc. they also have a target that they head towards; either a station or a wyrmhole. They're spawned from a station or from a random position (with hyperspace particles) to pretend that they've just jumped in. I'd love to have more persistent NPCs, but I probably spent too many tokens, performance and cart space on them already.</p> <p>One of the more interesting problems to solve was how to stop NPCs spawning in a position then flying towards a target on the other side of the system's sun without them hitting it. I don't check them for collisions so they'd just fly right on through blissfully unaware of any problem. Given the player can't do that it was a bit non-ideal to witness ships emerge from the superhot plasma if you happened to be flying close to the sun at the time. It got even more obvious when I stopped pausing the simulation in the System Map since you could watch the NPCs sun-diving:</p> <img style="" border=0 src="/media/47206/space_20.gif" alt="" /> <p>I tried various clever solutions with trigonometry and mathematics, but they never worked very well. In the end, I solved this problem with a hack. Whenever an NPC is generated their journey is quickly simulated, start to finish, but with coarser framerate. If they get too close to the sun then that journey is ditched and the NPC journey is generated again until a valid journey is produced. This does make for the occasional performance spike, but on the whole works quite well and for few tokens.</p> <p>There's a cap on the number of NPCs per system that takes into account the number of weevils to try and make sure there's quite a bit of performance headroom, just in case.</p> <h2>Enemies</h2> <p>To be honest, I was having so much fun making a pretend universe that I left it quite late to add in a challenge to the game. Eventually I admitted that I needed villains so I drew on personal history.</p> <p>A few years ago we found weevils in our kitchen. All over our kitchen. Eventually we tracked them back to a bag of birdseed that now moved and crackled by itself...</p> <p>The next hours and days consisted of rooting out weevil and destroying it - weevils became a kind of bogeyman in our house. Nothing is more evil than weevil in our home.</p> <p> <table><tr><td width=128> <img src="https://www.lexaloffle.com/bbs/gfxc/47206_1.png" width=128 height=128> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_47206_1"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/47206_1.txt", function (retdata){ var el = document.getElementById("gfxcode_47206_1"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [32x32]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_47206_1" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> </p> <p>I wanted to make each weevil unique, but in the end they are all based on the same code with varying attributes. As the game goes on more and more dangerous weevils are generated ahead of the ship within a random circle depending on how dangerous the system is and the difficulty level of the game. Some weevils can hit the ship and damage it with their collision, all weevils fire missiles at the ship at different rates and for different amounts of damage.</p> <h3>Space is Big, even PICO Space</h3> <p>One of the biggest problems with the weevils was how to make them possible to fight on the tiny 128x128 PICO-8 screen without making them too slow to stop a player just flying past them. I didn't want to slow down the player either, since getting between locations was taking long enough already. Besides, when I tried slowing the ship, it just felt... bad.</p> <p>I think the weevils are still a bit too fast to be fair - I'm not convinced that I really solved this problem entirely.</p> <p>WARNING SPOILERS - DO NOT READ IF YOU WANT TO LEAVE THE ENDING AS A SURPRISE<br /> <div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <h2>Weevil Queen</h2> <p>I wanted an ending and a &quot;boss&quot; and so I did some research into big weevils (as you do). It turns out that there are some big ones out there and there are even some that live like ants with a queen. Not to the same scale as ants though.<br /> Add a bit of poetic licence and I came up with the weevil queen that's in the game.<br /> What do you mean: &quot;there isn't one?&quot;<br /> Are you saying you've not completed enough missions to gain the Prototype Scanner upgrade, located the Weevil Base and jumped into the system to fight the Weevil Queen and save the galaxy?<br /> At time of writing, I'm not sure anyone has except me (many testing times). If you have I'd really like to know (please?).</p> <p>The Weevil Queen is generated in a system that has only one wyrmhole in it (a leaf node in the galaxy &quot;tree&quot;) and is by default hidden in the Galaxy Map (and the wyrmhole to it is hidden in the system containing it too). Some of the changes for the weevil system happen during galaxy generation. Most of it is done on entry. There are no space stations or NPC ships and the weevil queen is added. She behaves a lot like a normal weevil, but she has hitboxes at the back of her that don't take damage and she moves more slowly. She fires the most deadly missiles, most frequently. She may also teleport randomly if hit.<br /> The weevil queen is drawn using several sprites together and she gyrates at a speed according to how close to destruction she is.<br /> <table><tr><td width=128> <img src="https://www.lexaloffle.com/bbs/gfxc/47206_2.png" width=128 height=128> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_47206_2"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/47206_2.txt", function (retdata){ var el = document.getElementById("gfxcode_47206_2"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [32x32]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_47206_2" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> <table><tr><td width=128> <img src="https://www.lexaloffle.com/bbs/gfxc/47206_3.png" width=128 height=128> </td> <td valign=bottom> <a style="cursor:pointer;font-size:8pt" onclick=' var el = document.getElementById("gfxcode_47206_3"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("https://www.lexaloffle.com/bbs/gfxc/47206_3.txt", function (retdata){ var el = document.getElementById("gfxcode_47206_3"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [32x32]</a> </td></tr> <tr><td colspan=2> <textarea rows=3 class=lexinput id="gfxcode_47206_3" style="width:640px;background-color:#fed;display:none;overflow:hidden; font-size:6pt;"></textarea> </td> </tr> </table> </p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function(q) pal(15,0) local en=5-q.life/10 local sn48,cs48,sn32,cs32=sin(p/48*en),cos(p/48*en),sin(p/32*en),cos(p/32*en) q.x+=sn32 circ_orig(p%96,g_sys.sun.pl[q.life\10+1]) spr(135,-25+sn48,-10+cs48,2,2) -- right front leg spr(135,11-sn32,-10-sn48,unpack_split'2,2,1') -- left front leg spr(135,-29,cs32-52,2,2,nil,1) -- right back leg spr(135,13,cs48-52,unpack_split'2,2,1,1') -- left back leg spr(137,12+sn48,-26+sn32,unpack_split'2,2,1,1') -- left back leg spr(137,-27-cs32,-26+cs48,2,2,nil,1) -- right back leg spr(128,sn48-15,unpack_split'-50,2,4') -- right wing spr(130,-sn48,unpack_split'-50,2,4') -- left wing spr(132,cs48-13,unpack_split'-29,3,4') -- thorax spr(139,-10+cs48,-8-sn32,3,3) -- head reset_dr_pal() end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>When she is destroyed, she is changed into the Intergalactic Wyrmhole that leads to the next (harder) galaxy, the weevil system loses its weevil flag and all the weevils are destroyed.</p> <p>I spent a lot of time getting all this to work, all the time wondering if anyone will ever see it.<br /> </div></div></div></p> <h2>Tables and &quot;Objects&quot;</h2> <p>I'm not much of an object oriented zealot (learning to program in BASIC in the 80s does that to you), but for the entities in PICO Space I used tables as objects of a kind.<br /> Things like planets, stations, weevils (called aliens in the code) and NPC ships generally have &quot;standard&quot; attributes (x,y for position, bounding box for draw culling etc.) and functions (update and draw).<br /> On entering a system an &quot;updateables&quot; and a &quot;drawables&quot; table is populated with appropriate things from those tables in the current star system and the update and draw functions loop through these and call them as appropriate. Using the CAMERA function I set the origin for drawing to reflect the object's position then the draw function draws from there. Things with a map function get drawn on the System Map etc. It works quite well and feels a bit like adding components to entities.<br /> I had a lot more separate lists and loops for these early on just to get going - I find doing things &quot;the dumb way&quot; first and improving it later works well for me (along with, if it ain't broke don't fix it...).</p> <p>Some things e.g. particles are kept separate still, for speed.</p> <h2>Particles</h2> <p>There are two big types of particle in PICO Space. Points and circles. There's a function to add both of these in a single line each. They have a lifetime, position and update functions.</p> <p>Points have two update functions - a typical velocity update one and a more abstract randomly swapping x and y velocity update. The former is used in the explosions. The latter is most obvious in the hyperspace cloud at the very start of the game.<br /> Circle particles draw at a different size corresponding to the life left of the particle.</p> <p>Why do they look the way they do? It's the screen fade effect.</p> <p>See <a href="https://www.lexaloffle.com/bbs/?tid=41149">https://www.lexaloffle.com/bbs/?tid=41149</a> for more information.</p> <h2>Menus</h2> <p>All the menus use the same code and are driven by data passed to them. There's nothing amazingly clever about them (or that), but I found it was much nicer in every respect to work with them once I took this approach. So I suggest writing generic menu routines soon if you find you're needing more than one of the things in a project - don't put it off.</p> <h2>Memory and Performance</h2> <p>PICO-8 makes both of these things really easy - Ctl/Cmd P along with a constant print of stat(0) if it went above a threshold value (usually 1024).<br /> The latter helped me find a nasty problem very near release. For a long time I'd paused the game except when flying the ship in space, but particles were drawn and deleted in the draw function. When I enabled the game to update, even while in the maps and docked, I was generating particles (NPC ship engines, NPC hyperspace, sun flares), but never deleting them. So I'd run out of memory. Sometimes after a very long time. It happened much faster when I moved the cursor about in the map views so I spent ages debugging those to no joy only to eventually realise that I was running out of memory due to the ship engines firing a bunch of particles out into my dwindling memory...</p> <h2>Loading and Saving</h2> <p>I was very worried about getting the load and save functions to work, especially with the web player, but in the end it was very easy. Dump some values into cartdata to save, read them back when loading. I'm presuming the browser cache gets these when playing in a browser(?).<br /> One slight downer is the paste codes don't work on the web. They seem to work fine in &quot;native&quot; PICO-8 though and the &quot;binary&quot; versions. It's the only thing that doesn't work there.</p> <p>The best thing about having save games was for testing during development. I built up a text file with a long list of different saves that allowed me to test different stages in the game, different galaxies and systems etc. I could edit them a bit to quickly test some things as well.<br /> I'd highly recommend implementing something like this if you have a longer game and want to test it - especially since it's something your players might be able to use too.</p> <img style="" border=0 src="/media/47206/space_37.gif" alt="" /> <h2>Tokens</h2> <p>As you may have gathered if you read this far, I ran out of tokens.<br /> Procedural generation produces content from code in preference to pre-defined content in storage so it wasn't overly surprising. I've seen others struggle with memory for proc gen, but I found the 2MB limit wasn't ever a problem.</p> <p>A large amount of the end of development involved trying to save tokens.</p> <p>Look out for my followup post about that, working title: &quot;A desperate programmer's attempts to squeeze galaxies into a PICO-8 cart&quot;</p> <p>--<br /> If you have any questions about the above post or anything else to do with PICO Space please ask them below and I'll try to answer them (or maybe even extend this article even further).</p> https://www.lexaloffle.com/bbs/?tid=42353 https://www.lexaloffle.com/bbs/?tid=42353 Fri, 09 Apr 2021 15:46:00 UTC PICO Space <h1>PICO Space</h1> <p> <table><tr><td> <a href="/bbs/?pid=89915#p"> <img src="/bbs/thumbs/pico8_drakeblue_picospace-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=89915#p"> drakeblue_picospace</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=89915#p"> [Click to Play]</a> </td></tr></table> </p> <p><em>v1.1</em><br /> Defend the animals of the galaxy from the space weevil invasion in your grandad's space taxi!</p> <p>Check the notice boards at space stations for prospective passengers. Gain rewards when they're delivered safely and discover how to defeat the weevil menace.</p> <p>The galaxy is quickly becoming a more and more dangerous place so be careful out there - with 50-70 systems and some questionable government policies an animal needs to look after themselves!</p> <p><strong><em> Please report any bugs or if something is unclear below. Feedback helps me improve and is always welcome :) </em></strong></p> <h2>Controls</h2> <img style="" border=0 src="/media/47206/spacecontrols.png" alt="" /> <h3>Main Menu</h3> <ul> <li>Use Up, Down and X to select options in the menus. </li> <li>Return/Start/P will always take you to the Main Menu</li> <li>Hold Return/Start/P to access the normal PICO-8 menu.</li> </ul> <p>I recommend a gamepad if you have one, but keys work fine too. Holding the X and O buttons together is useful to use the ship flip ability successfully. On mobile, I've found swiping my thumb backwards and forwards between the X and O buttons works okay, but it does seem easier to play with keys or a gamepad (to me at least).</p> <h2>Starting the Game</h2> <img style="" border=0 src="/media/47206/space_46.gif" alt="" /> <p>Use the up and down directions to highlight an option and X to select it.</p> <ul> <li>Begin New Game - starts a new game with the currently show captain in a new galaxy (Captain Magerquack by default).</li> <li>Change Captain - chooses a new captain and galaxy with which to start a new game using the Begin New Game option. This doesn't affect the currently stored game or any game from a pasted code.</li> <li>Continue Last Game - this retrieves the previously auto-saved game from your browser's cache or PICO-8's cartdata. The game is saved at the Dock Menu and on entering a system via a hyperjump.<br /> If you want to preserve further game states beyond this then use the next option.</li> <li>Load From Pasted Code - every time the game is saved PICO Space places a save game code into the clipboard. By pasting this code into a text file or similar then multiple game saves can be maintained. To restore from one of these codes:<br /> &gt; - copy the code into the clipboard from the application you've used to store it<br /> &gt; - switch back to PICO Space running in PICO-8 and paste it<br /> &gt; - Use X to select the Load From Pasted Code option in the menu</li> </ul> <p>NOTE: THIS DOESN'T SEEM TO WORK IN THE BROWSER - YOU WILL NEED TO DOWNLOAD THE STANDALONE PICO-8 CONSOLE VERSION TO LOAD FROM SAVE CODES OR ACCESS THE GAME THROUGH SPLORE<br /> THE GAME WILL BEHAVE UNPREDICTABLY (PROBABLY CRASH) IF A MALFORMED CODE OR OTHER DATA IS PASTED INTO IT</p> <ul> <li>Set Difficulty - Adjusts how dangerous the galaxy is in the game. This option affects new games only so needs to be set before choosing &quot;Begin New Game&quot;.<br /> &gt; - Easy - for casual or inexperienced players, but still with some challenge<br /> &gt; - Normal - a reasonable challenge, success is not guaranteed on each journey<br /> &gt; - Hard - a difficult game likely to require multiple reloads</li> </ul> <p><strong><em> Please tell me if you think these ratings aren't very correct so I can try to tweak them </em></strong></p> <h2>How to Get Around the Galaxy</h2> <p><em>(the following is an extract from the dog-eared manual you found in the glove compartment of your grandad's ship)</em></p> <p>Congratulations on your purchase of a Farwilre P1C0 Star Taxi!</p> <img style="" border=0 src="/media/47206/space_47.gif" alt="" /> <p>Your ship will enable you to fly anywhere within a system's boundary by directing it with the arrow keys or control stick (if fitted). Be careful of flying into a system's sun as there may be undesirable explosive consequences.</p> <ul> <li>The Short Range Scanner is useful to see what's close to you and is located in the bottom right of the viewscreen.</li> <li>The current system or current target (with distance in standard galactic units) is shown in the top left.</li> <li>Your ship's remaining shield energy is displayed in the bottom left. If this is depleted then it will flash to indicate that you should dock at the nearest space station for recharging.</li> <li>To locate space stations or other objects within a star system press Return, Start or P to bring up the main menu.</li> </ul> <h2>Main Menu (Pause)</h2> <img style="" border=0 src="/media/47206/space_48.gif" alt="" /> <p>Select the System Map (with Up, Down and X) from the options shown.</p> <h3>System Map</h3> <img style="" border=0 src="/media/47206/space_53.gif" alt="" /> <p>Solar systems are large so to avoid excessive journey time it is advised to utilise your ship's hyperdrive from the System Map (where traffic laws permit).</p> <p>To do this:</p> <ul> <li>Locate the cursor where you wish to jump to by using the direction keys</li> <li>Press O, Z or V to execute a hyper jump</li> <li>Press X to target the nearest system object. The target is shown in the top left and also indicated by a red marker.</li> </ul> <p>Note: be sure to peruse the System Map in a safe location to avoid possible accidents while it has your attention. Last year 45% of ship accidents happened while pilots were viewing their map screens - don't let the next one happen to you!</p> <p>Systems in PICO Space are linked by Hyperspace Wyrmholes (of as yet unknown origin). These can be used to traverse between stars even in ships that are unequipped with an interstellar-capable drive. Thus to travel to another system simply fly into the centre of a wyrmhole and your ship will travel through hyperspace to a point in the system indicated in the wyrmhole's name.</p> <p>If you know which adjacent star you wish to travel to, it is easiest to find where the wyrmhole to it is by using the System Map.</p> <p>To navigate about the greater galaxy and hence determine which wyrmholes to use it is advisable to examine the ship's Galaxy Scanner.</p> <h3>Galaxy Scanner</h3> <img style="" border=0 src="/media/47206/space_50.gif" alt="" /> <p>The Galaxy Scanner will open centred on your current location - shown by the ship icon and expanding circle indicator. Adjacent stars (i.e. those which are connected by a pair of wyrmholes) have lines drawn between them. Systems adjacent to your current location have green lines drawn to them. Corresponding wyrmholes should be visible on the System Map.</p> <p>The view and cursor in the centre may be moved using the direction keys. The currently highlighted system will be the closest to the cursor position.</p> <p>The galaxy is quite large so for optimal viewing it may be necessary to zoom the view in or out by holding the X key and using the Up and Down directions to change the scale of the view.</p> <p>If your ship is fitted with an Interstellar Drive then it is possible to hyperjump (without traversing a wyrmhole) to adjacent systems by highlighting them with the cursor in this view and pressing O, Z or C.</p> <h3>Status</h3> <p>At any time your current status can be checked from the Main Menu by selecting this option.</p> <img style="" border=0 src="/media/47206/space_55.gif" alt="" /> <p>The screen shows:</p> <ul> <li>You, the captain of the ship and your combat rating</li> <li>Any current message</li> <li>Your current passenger if one is present and to where they wish to be taken.</li> <li>Information about any upgrades that have been added to your ship</li> <li>The energy level remaining for you ship's shields</li> <li>The danger level of this galaxy</li> </ul> <h2>Weaponry</h2> <p>Should you be unfortunate enough to encounter a hostile threat on your travels your P1C0 Space Taxi is fitted with a standard P3W Blaser; a small but adequate defensive weapon.</p> <ul> <li>Tap X (and release) and the P3W will fire</li> <li>Hold X to charge multiple shots that will rapidly fire on releasing the trigger.</li> <li>Note: while energy is diverted to charging the P3W your shields are unable to recover strength.</li> </ul> <h2>Dock Menu</h2> <p>When docked at a space station the following standard options will be available:</p> <img style="" border=0 src="/media/47206/space_56.gif" alt="" /> <h3>Notice Board</h3> <p>Waiting passengers are listed here for an enterprising space taxi owner to transport to their desired destination.</p> <img style="" border=0 src="/media/47206/space_57.gif" alt="" /> <p>Use the Up, Down and X keys to select a passenger that you wish to transport. Be careful to choose a journey you can complete - an animal never backs out of a deal!</p> <h3>New Paint</h3> <p>Choose from a range of desirable colour schemes to customise your Farwilre pride and joy!</p> <h3>Launch to Space</h3> <p>The station will launch you back to space so you may continue on your journeying.</p> <p><em>extract ends</em></p> <h2>Tips</h2> <ul> <li>Choose your passengers wisely - some wish to travel further than others. Check on where they want to go via the Galaxy Map before committing to a journey you aren't sure you want to take.</li> <li>Plan your journey before leaving the safety of the space stations.</li> <li>If your shields are damaged it may be wise to stop at a station on the way to your destination to recharge them.</li> <li>Charge your weapon before encountering enemies, but don't hold X constantly as it stops your shields recharging as you fly.</li> <li>Use your hyperspace ability within systems to save on journey time or to escape a tough spot, especially as the galaxy becomes more and more dangerous.</li> <li>Note that the game is only paused in the Main Menu, other screens don't freeze time.</li> </ul> <p>If you are not sure what to do:</p> <ul> <li>try ferrying passengers</li> <li>later in the game, try reading the Beeb News or listening to what the NPC ships say to you.</li> </ul> <p>Good Luck, Captain!</p> <h2>V1.1</h2> <ul> <li> <p>UI colour changes</p> </li> <li> <p>fade effect improved</p> </li> <li> <p>screen shake added</p> </li> <li>difficulty reduced (a bit); enemies are slower, shots do less damage</li> </ul> https://www.lexaloffle.com/bbs/?tid=42279 https://www.lexaloffle.com/bbs/?tid=42279 Sat, 03 Apr 2021 16:56:27 UTC Fading Stars <h1>Fading Stars Demo</h1> <p> <table><tr><td> <a href="/bbs/?pid=86396#p"> <img src="/bbs/thumbs/pico8_fading_stars-6.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=86396#p"> fading_stars</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=86396#p"> [Click to Play]</a> </td></tr></table> </p> <p>Demo showing the combination of the stars and fade effect I used in PICO Space: <a href="https://www.lexaloffle.com/bbs/?tid=42279">https://www.lexaloffle.com/bbs/?tid=42279</a>.</p> <p>[UPDATE 2021-4-12: 8bit and 16bit cached modes (explanation below and in code), some other small tweaks]<br /> [UPDATE 2021-5-6: added interleaved 8bit mode]</p> <h2>Stars</h2> <p>The stars are just simple particles that have x,y,z coordinates.</p> <p>In this demo I use a couple of sin functions to give them some movement combined with a divide by the z coord for a bit of parallax. In game, I feed in the player's position.</p> <p>Then I clamp the resulting x,y values to the screen with the modulus operator so they're always visible (%128). It does mean that the same stars go past constantly, but otherwise I was processing a lot of particles that don't get seen very often (not aiming for realism here).</p> <h2>Fade Effect</h2> <p>This works by mapping the colour of every pixel on the screen to another colour that tends to a target e.g. 0/black.<br /> You can use a similar mapping with the pal(x,1) function to e.g. do fades to black between screens etc. but that fades everything including anything drawn that frame.</p> <p>In this demo I process the pixels already in screen memory so that the screen is faded by a step, then draw fresh stars on top of that.</p> <p>It's pretty expensive to do the whole screen (IIRC about 90% of performance at 60fps) so I've set it up to do every fourth scan line, starting from a different point each frame. Effectively a quarter of the screen is faded at a time. It takes 4 frames to fade the whole screen one step.</p> <p>I initially tried fading in quarter strips top to bottom, but the tearing on bigger objects like planets looked pretty bad.</p> <p>Using the order 0,2,1,3 for the scanlines does some rough dithering to make the effect look a bit more uniform. A random value flr(rnd(4)) works quite well too, but is messier looking.</p> <p>Since I found using poke4 to work on 8 pixels at a time was fastest (not surprising really) dithering horizontally is limited and isn't in the demo. Nevertheless, I keep meaning to try a &quot;Z&quot; pattern i.e.</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre> 0000000011111111 2222222233333333</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>I'm concerned it might cost too much more in performance/tokens for too little visual improvement.</p> <p>[edit]<br /> Of course, as soon as I write about it the old subconscious starts working away and it takes 5 minutes to implement just that - a reverse N pattern as it turns out. Same performance, same tokens. See the new cart.</p> <h3>Pros of Effect</h3> <ul> <li>You can draw whatever you want really and the effect essentially &quot;just works&quot; as a replacement for a cls().</li> <li>Cross-fading out from a scene just happens &quot;free&quot;.</li> <li>very simple particles look much more complicated than they really are</li> </ul> <h3>Cons</h3> <ul> <li>You can't draw anything that moves without the fade effect &quot;catching&quot; it. It can be mitigated by drawing around your objects (e.g. black borders), but if the view moves more than the width of the border you're out of luck.</li> <li>Conversely, the effect only works where you don't draw that frame - so if your game has e.g. a full-screen scrolling background that's drawn every frame then you won't see any effect at all. For a <em>space</em> game this isn't a huge problem, but it's still visible here and there. </li> <li>If nothing moves then there's no effect - try hacking the stars to be still in the demo.</li> <li>Performance cost is approx 21% at 60fps.</li> <li>Obv costs some tokens.</li> </ul> <h2>Caching</h2> <p>The effect works fine by extracting each pixel's colour value via shifting and masking then dumping the mapped values back onto the screen, but it's still pretty performance heavy.<br /> When I was writing PICO Space I'd read a few times that procedurally generated content used a lot of memory so I didn't want to try anything like the following, but now I have a much better idea of the game's memory requirements I thought I'd give it a go.</p> <h3>8-bit Mapping</h3> <p>Pixels in PICO-8's screen are determined by a 4-bit value, but peeking and poking only works with 8-bit granularity at best i.e. a pair of pixels or more at once. The mappings I have contain 16 values for each possible colour of a pixel.</p> <p>Considering pairs of pixels instead of single pixels, there are 16 * 16 = 256 possible combination of colours that need to be mapped. Why not store a table with each of these values - it can't be that large, right?</p> <p>Turns out it isn't, especially when compared to the 2MB of space lua is given in PICO-8. In fact the demo seems to only use about 2K or so (which is still a lot more than the 256 bytes it <em>should</em> take, but still pretty small).</p> <p>This means that a lot of masking and shifting isn't as necessary inside the inner loop. It even takes fewer tokens. The performance improvement is enough that half or even all of the screen being processed per frame isn't too bad.</p> <h3>16-bit Mapping</h3> <p>The next step was obviously to try mapping 4 pixels at a time using 16-bit values.</p> <p>This would need a table of 16^4 = 65536 entries which isn't very big for a modern machine, but is pushing it pretty far for PICO-8. It's possible - take a look at the code. It also takes up a <em>lot</em> more memory: about 1200KB it seems. That's well over half of the total space available and for my purposes in PICO Space is enough to give me sporadic out of memory errors as it stands (PICO Space takes about 600-900KB depending on the size of the current galaxy and how much is going on in it at any particular moment). For other games it may be absolutely fine and it's tempting since there's about a 2x speed-up compared to my original implementation of the effect using this technique.</p> <h3>A Bit Too Far</h3> <p>PICO-8's number format is 16bit.16bit fixed point so every value I've been storing so far is actually 32 bits in size whether I use all of those bits or not. Why not use them all?</p> <p>Storing mappings for 8 pixels isn't going to work: 16^8 = 4,294,967,296 - a bit too much for PICO-8.</p> <p>Instead, the last implementation that I've tried (so far) stores two 16-bit values in each number in the cache table so that the same amount of mapping values as in the previous section takes half the entries and hence half the space. The upper 16 bits take the even values; lower 16 bits the odd values.</p> <p>This brings the memory usage down to about 600KB or so, which is fairly reasonable.</p> <p>Unfortunately, the two mapping values packed into a single PICO-8 table value need to be unpacked to be used in the inner loop of the effect. By the time shifts and masks are applied to do this I couldn't get the performance to really be any better than the original effect (without any caching of values), never mind faster than the other cached value versions.</p> <h3>Yet Another Way</h3> <p>Up until this point I'd only considered making the effect faster and not &quot;better&quot;. Two horizontally adjacent pixels are represented by each byte in the screen so one of the first compromises I'd made was to assume I couldn't fade these separately per frame and so fading the whole screen over four frames was done with at least chunks of two horizontally adjacent pixels at a time.<br /> Since the 8bit cache version uses so little memory, is faster and deals with all combinations of two pixels both fading on the same iteration it struck me that there wouldn't be much cost to keeping two caches of 8bit values, one with the left side pixel faded, one with the right and swapping which cache is used per frame. When combined with alternating which rows are processed, this allows a dither pattern that works on a block of 2x2 pixels - no more horizontal chunking:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>01 23</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=41149 https://www.lexaloffle.com/bbs/?tid=41149 Tue, 12 Jan 2021 15:57:44 UTC Demystifying the Christmas Tree <p> <table><tr><td> <a href="/bbs/?pid=85468#p"> <img src="/bbs/thumbs/pico8_demystify-3.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=85468#p"> demystify</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=85468#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Demystifying the Christmas Tree</h1> <p>Help your kitten destroy as many decorations as you can before the tree is fully decorated or their energy runs out and they nap.</p> <p>Try to destroy multiple decorations within a short time to get combo bonuses and improve your score. Use your energy wisely, young feline.</p> <p>Play as Philly or Frankie on their own or with a friend against each other. See who can cause the most chaos!</p> <h2>Controls</h2> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>Action Frankie (Player 1) Philly (Player 2) jump up E run left/right S, F descend down D poke O(Z) W swipe/hit X Q Return menu, including music on/off and restart.</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(These are the standard PICO-8 controls so some other keys work too)</p> <h2>Background</h2> <p>Demystifying the Christmas Tree recreates a real event from a Christmas past, although in real life the kittens not only broke decorations, but also took out parts of the tree itself. They also didn't run out of energy (as anyone who has had kittens would know).</p> <p>If you like this game, find a problem or have any suggestions then please comment below.</p> <p>Please consider trying my other games or following me for news on new projects.</p> <p>Happy Holidays :)</p> <p><strong>1.0.1 update:</strong> after testing with the owner of the kittens (my girlfriend's mother aka &quot;mother-outlaw&quot;) I've added an option to change the speed that the arms decorate the tree.</p> <p><strong>1.0.2 update:</strong> added fade effect to intro. Because I felt like it.</p> <p><strong>1.0.3 update:</strong> added combo indicator after user feeback.</p> https://www.lexaloffle.com/bbs/?tid=40826 https://www.lexaloffle.com/bbs/?tid=40826 Wed, 16 Dec 2020 13:32:01 UTC Silly Snow <h1>Silly Snow</h1> <p> <table><tr><td> <a href="/bbs/?pid=84926#p"> <img src="/bbs/thumbs/pico8_db_silly_snow-3.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=84926#p"> db_silly_snow</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=84926#p"> [Click to Play]</a> </td></tr></table> </p> <p>(update: added 2 new methods that incorporate gusts of wind)</p> <h2>Controls</h2> <p>UP/DOWN chooses different behaviour for the snow flakes<br /> X changes the colour of the falling snow so you can see the &quot;trick&quot; a bit easier<br /> O/Z toggles drawing the non-snow bits of the graphics each frame on and off</p> <h2>What it is</h2> <p>--</p> <p>TL;DR<br /> Only track falling snow, add lying snow to the background.</p> <p>--</p> <p>As it's that time of year again, I thought I'd write some winter-themed stuff.</p> <p>This is my take on ye olde faithful falling snow demo, which I'm using for the intro screen for another cart (on its way soon). I've cleaned it up a bit, added way more comments than I normally do and added some options to show what's happening a bit and show some variations. Click &quot;Code&quot; below the display above if you're interested.</p> <p>I first typed in a version of this demo from a magazine back in the mid 80s on an Atari 800XL. In the 35ish years since then I'm not sure I've ever implemented it again though.</p> <p>The gist of how it works:<br /> Falling snow is represented by a collection of simple particles that are represented by a position (x,y). Each frame that position is updated (mostly downwards i.e. y+=some_dist).<br /> If the snow flake encounters an obstacle (i.e. a pixel that isn't empty or the bottom of the screen) then the snow flake has landed. </p> <p>Tracking snow flakes after they've landed isn't practical (even with PICO-8 and it certainly wasn't with an 800XL) and is also a bit pointless since once a snow flake has landed, it aint going anywhere. Well, at least not in this demo. Instead, the particle is destroyed and the pixel where it landed is set to white and becomes part of the background (in this demo that means it has a colour greater than 1).<br /> This is an incredibly basic version of how a lot of &quot;physics&quot; engines work: updating only moving or otherwise interesting parts of the simulation and &quot;parking&quot; the rest. Usually they'd check the stationary particles in some way for whether they need to be activated. If you wanted to simulate collapsing drifts etc. there's nothing really to stop you keeping a record of where the snow has fallen or scanning for white pixels and perhaps checking to see if a condition to collapse has been met. Then you could find all the snow pixels affected by the collapsing pixel and &quot;wake&quot; them up. You would probably need to check at a slower than per frame rate for performance reasons.</p> <p>As with most sims the fun is in playing about with it, hence the 9 method variations in the cart e.g.</p> <ul> <li>the exact behaviour of the flakes in the air</li> <li>whether they land or slide to the side on encountering the background can be tweaked.</li> <li>wind gusts...</li> </ul> <h2>Blustery Blizzards</h2> <p>Methods 8 and 9 add a wind factor to the updated position for each flake generated by a value derived from complex and deep trigonometric knowledge (aka trial and error). The nice thing about this is it's only calculated once per frame and only added per snow flake so it's very cheap. Adding sin values per flake based on the flake's position gives some odd results.</p> <h2>Limitations</h2> <ul> <li> <p>for there to be stationary, landed snow relies on not clearing the screen. If you clear the screen then you're pretty snow drifts all disappear. You can still have snow flakes falling, but they will disappear a frame after they land...</p> </li> <li> <p>The methods in this cart are fairly non-destructive of the background, but it's fairly easy to make a version that &quot;eats&quot; into what's already on the screen (acid snow!). I've included an option to re-draw the background each frame. As long as your background doesn't move then it works fine (remember, no screen clear).</p> </li> <li>&quot;tunneling&quot; through thin parts of the background varies in frequency depending on your method. Generally, the more random the snow flake movement, the more problems you'll have.</li> </ul> <p>On the Atari ST there was a game based around this that I got from a magazine cover disk called &quot;Downfall&quot;. I could only find one video of it and the uploader doesn't seem to really understand how to play it sadly.<br /> You were supposed to compete against a friend to draw lines to funnel snow from your side out of a hole at the bottom that would then be sent to their side (and vice versa). You could also funnel snow to the sides to give you energy for &quot;special powers&quot; that let you e.g. draw lines on your opponent's side.</p> <p>I expect that explanation's as clear as a blizzard; hopefully the code isn't as bad.</p> <p>Happy holidays :)</p> <p><object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/SHZB9nIzZ64&hl=en&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/SHZB9nIzZ64&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> https://www.lexaloffle.com/bbs/?tid=40631 https://www.lexaloffle.com/bbs/?tid=40631 Wed, 02 Dec 2020 12:47:35 UTC The Pico Mermaid <h1>The Pico Mermaid</h1> <p> <table><tr><td> <a href="/bbs/?pid=84034#p"> <img src="/bbs/thumbs/pico8_thepicomermaid-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=84034#p"> thepicomermaid</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=84034#p"> [Click to Play]</a> </td></tr></table> </p> <p>Use (X) to control the Pico Mermaid as she fetches pearls from the bottom of the sea back to the surface. Avoid the piranhas that will swim faster and faster as the mermaid retrieves more pearls.</p> <p>This is my entry into Tweet Tweet Jam 5 and so the code fits into 560 characters (two tweets).</p> <h3>Features:</h3> <ul> <li>Single-button controls (X)</li> <li>Animated and multi-colour pixel art sprites*</li> <li>air and water physics*</li> <li>Two particle systems*</li> <li>Difficulty ramp*</li> <li>Score effect*</li> <li>Death effect*</li> <li>start animation*</li> <li>current score and high score display*</li> <li>in-game instructions*</li> </ul> <p>(* kinda)</p> <p>Here's the code:</p> <div> <div style="max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>P=pset::A::x=64y=0v=-9t=0w=127e=0d=.6s=0for z=0,29do poke(z\6*x+z%6+1,'0x'..sub('e0e800800880ce0800444404e008002444043b0000444480b000004088',1+z*2,2+z*2))end::B::P(69,e&lt;1and w or y,7)H=max(s,H)e=y&gt;119and 1or e ?'tAP❎ gET●:'..s..' hI:'..H v+=.5C=cls if(y&gt;8)v-=max(btnp(❎)and 2or.4,v-.6) flip()C(1)rectfill(0,0,w,9,12)t=(t+d)%w y=min(120,y+v)spr(0,x,y,1,1,t&amp;8&lt;1,e&lt;1)for i=3,14do d=-d t=-t h=40*i-t-4&amp;w pal(4,i)k=i*8k+=7*sin(h/w)if((h+4)\8==8and 4&gt;abs(k-y-2))C(8)goto A spr(1,h,k,1,1,d&lt;0)P(rnd(8)+x,h*d%y+3)P(k*d/.7,h\d)end if(y&lt;9and e&gt;0)e=0s+=1d*=-1.2C(7) goto B</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=40311 https://www.lexaloffle.com/bbs/?tid=40311 Mon, 09 Nov 2020 11:37:59 UTC P8C-BUN on Itch.io <p>P8C-BUN is now uploaded to itch.io here: <a href="https://drake-blue.itch.io/p8c-bun"><a href="https://drake-blue.itch.io/p8c-bun">https://drake-blue.itch.io/p8c-bun</a></a><br /> <object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/QmOxLX-82RY&hl=en&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/QmOxLX-82RY&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> <p>I've also been working on something else that I really want to share a preview of soon, but I need to clean it up just a little more first.</p> https://www.lexaloffle.com/bbs/?tid=40116 https://www.lexaloffle.com/bbs/?tid=40116 Mon, 02 Nov 2020 14:36:10 UTC P8C-BUN <h1>P8C-BUN</h1> <p> <table><tr><td> <a href="/bbs/?pid=83276#p"> <img src="/bbs/thumbs/pico8_drakeblue_p8cbun-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=83276#p"> drakeblue_p8cbun</a><br><br> by <a href="/bbs/?uid=47206"> drakeblue</a> <br><br><br> <a href="/bbs/?pid=83276#p"> [Click to Play]</a> </td></tr></table> </p> <p>Help your chosen bunny cover each level with poo then escape down a rabbit hole. Don't get caught by the fox or anything else that's out to get you!</p> <p>Finish all 16 levels without restarting to achieve &quot;Iron Bun&quot; or just try to post a high score. Start at whatever level you like.</p> <h3>Controls</h3> <ul> <li>Use the d-pad/arrow keys to direct your bunny.</li> <li>z/c/(O) to show where you haven't pooed yet.</li> <li>x to paws and return to the title screen.</li> <li>You can toggle the music or return to the title screen from the menu as well.</li> </ul> <h3>Tips</h3> <ul> <li>The buns will keep running in the direction you choose until there's no clear path in front of them so there's no need to hold down the arrow keys.</li> <li>If you choose a new direction before a junction or corner they'll remember that and turn immediately so corner early for maximum speed.</li> <li>The bananas will give you a speed boost, but leave skins behind that you (or the fox) may slip on.</li> <li>Macaroon is too tough to be caught by the fox or anything else so if you just want to play through the levels (or practice) choose to play as her. Real-life Macaroon has seen off cats and kills blankets on a regular basis.</li> <li>The fox gets faster and the red kite will fly over as you cover more levels so choose which level you start from wisely if you're aiming for Iron Bun.</li> <li>Manipulate the fox, especially using the rabbit holes, to make your life easier.</li> </ul> <p><object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/5PR46S5bCCA&hl=en&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/5PR46S5bCCA&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> <p>1.1 Update: text legibility and efficiency improvements<br /> 1.1.1: restored kite spawn to be after a few levels and not right from the beginning.</p> <p>This is my first PICO-8 game (in fact, my first full game for anything) so any feedback is welcome. More info about P8C-BUN is here: <a href="https://drakeblue.com">DrakeBlue.com</a>.<br /> This game was inspired by our real-life pet rabbits (especially Oreo, who does tend to poo everywhere) and exists thanks to the patience of my gf (who runs the rabbit-oriented website mentioned on the title screen <a href="https://rabbitretail.co.uk">RabbitRetail.co.uk</a> and uses it to help donate to rabbit charities and rescues as well as feed ourselves and our own bunnies).</p> <p>Purchase to download and support more development and bunnies here: <a href="https://rabbitretail.co.uk/products/p8c-bun-game"><a href="https://rabbitretail.co.uk/products/p8c-bun-game">https://rabbitretail.co.uk/products/p8c-bun-game</a></a></p> <p>Or here: <a href="https://drake-blue.itch.io/p8c-bun">Drake Blue on Itch.io</a></p> https://www.lexaloffle.com/bbs/?tid=40018 https://www.lexaloffle.com/bbs/?tid=40018 Sat, 24 Oct 2020 11:46:09 UTC