As I was writing Save Yourself I needed some proper debugging methods to speed up finding bugs. Because my game was almost over token and char limit I had to completely scrap debug code at the end of the cycle. So I thought moving this debug to other cart may help someone in same need as I was.
- Prints messages with time (in seconds) attached.
- Deals with strings, numbers and nils
- Ability to control number of messages shown
- Ability to use spam filter - useful when you debug something every frame
- Show cpu consuption for update and draw method
- Have space for player coordinates and additional info visible below messages
Code is non minified and commented. Feel free to ask questions.
Edit: occured to me I could add ability to change how much of a screen debug messages take. I will add this in a update, when I get some time to do that...
Save Yourself v1.0c
Short adventure game with unique talking mechanic with focus on exploring and talking to NPCs. Meant to be played several times to learn the world and find clues. Game have random elements to throw player off from obvious resolution.
As it was my first released game it isn't very player friendly and is very obtuse in what it requires from you.
One run length: 5-20 minutes
You are one of many bounty hunters that is after Maggus, the royal mage, after you found King will pay handsomely for this task.
Allied mercenary lead you to enclosed, old, valley mine, where Maggus could hide.
This is your chance, there is only one exit from this place and your companion is guarding it.
There is only one catch, you have only two days - King will pay three times more if you deliver your bounty within specified time.
- semi hotfix for bug reported in this post by Sibwara (even though character can still stuck in ground, it will always have ability to climb back above ground)
- hotfix for not working ladders, reported in this post by orangecode
- fixed bug reported in this post by Sibwara
- restored acknowledging (sometimes) player making statement by npcs
- Initial release
You have my permission to use/modify any fragments of the code provided, crediting is nice but not required.
You DON'T have my permission to use any music or graphics used in this game.
Non-minified version with comments: BitBucket repository page
At Itch.io: Itch.io page
Any feedback or just sharing your experience is encouraged.
Data composition based on, collision system, snow and clouds rendering taken from, game: celeste by matt thorson + noel berry
String data storage, and functions for those, based on this post.
Hello, I am hitting token count with my game so often - it is irritating. I feel like I am fighting a war of having clean code vs having less tokens.
(I understand that pico8 is for small games and first step should be cutting features though)
I am not sure if something is wrong or am I expecting too much and trying to use pico8 like modern framework.
In the docs is stated:
One program can have a maximum of 8192 tokens. Each token is a word (e.g. variable name) or operator. Pairs of brackets, and strings count as 1 token. commas, periods, LOCALs, semi-colons, ENDs, and comments are not counted.
Let's look at this code:
(taken from my game, but shortened and altered - don't expect this to work! I am not saying that provided code is greatest piece of clean, descriptive code!)
It draws (on local space - screen) piece of text, npc will say to the player - after delay, with black background to ensure readability.
draw_say=function(this,x,y) x=this.x-x y=this.y-y palt(0,false) foreach(this.draw_message_queue,function(obj) local deltatime=gl_app_time.timeelapsed-obj.time local text_len=#obj.m local text_size=text_len*2 local text_time=text_len/4.0 local x1=x-text_size-2 local x2=x+text_size+2 local y1=y-12 local y2=y-4 if deltatime<text_time then rectfill(x1,y1,x2,y2,0) print(obj.m,x1,y1+2,obj.color) end end) palt() end,
This code isn't perfect, there are still magic numbers or non descriptive piece of code like y1=y-12 - what this '-12' means?
But most important things (to me) are explained in local variables like: text_size (how much space string will take on screen) and text_time (how long text should be printed based on length of screen)
All of this pasted into empty cart gives token count: 100
If I change lines:
local text_len=#obj.m local text_size=text_len*2 local text_time=text_len/4.0
local text_size=#obj.m*2 local text_time=#obj.m/4.0
I get token count: 99
This wasn't bad change as '#obj.m' still can be quite descriptive (even more if this was '#obj.text'), but shows that using locals is quite wasteful if your value isn't reused more. So going with that logic, let's change more code:
If I change lines:
x=this.x-x y=this.y-y local deltatime=gl_app_time.timeelapsed-obj.time local text_len=#obj.m local text_size=text_len*2 local text_time=text_len/4.0 local x1=x-text_size-2 local x2=x+text_size+2 local y1=y-12 local y2=y-4 if deltatime<text_time then
local x1=this.x-x-#obj.m*2-2 local x2=this.x-x+#obj.m*2+2 local y1=this.y-y-12 local y2=this.y-y-4 if (gl_app_time.timeelapsed-obj.time)<#obj.m/4.0 then
I get token count: 95
This comes from removing text_size, text_time and deltatime, but didn't get anything from removing lines 'x=this.x-x' and 'y=this.y-y'. (which make x and y local space btw - yep bad naming from my part)
Code isn't so bad, yet, but let's compress this even more:
draw_say=function(this,x,y) palt(0,false) foreach(this.draw_message_queue,function(obj) local x1=this.x-x-#obj.m*2-2 local y1=this.y-y-12 if (gl_app_time.timeelapsed-obj.time)<#obj.m/4.0 then rectfill(x1,y1,this.x-x+#obj.m*2+2,this.y-y-4,0) print(obj.m,x1,y1+2,obj.color) end end) palt() end,
And now we have token count: 89!
(Have fun decoding this if you didn't wrote this/came back after long break.)
11 tokens.. now we are talking!
But why the f*k you only removed x2 and y2? Because those are only used once. But lets remove all those:
draw_say=function(this,x,y) palt(0,false) foreach(this.draw_message_queue,function(obj) if (gl_app_time.timeelapsed-obj.time)<#obj.m/4.0 then rectfill(this.x-x-#obj.m*2-2,this.y-y-12,this.x-x+#obj.m*2+2,this.y-y-4,0) print(obj.m,this.x-x-#obj.m*2-2,this.y-y-12+2,obj.color) end end) palt() end,
I get token count: 99!
So this shows that if you have more than one operation and you reuse it at least once, you should use variables for that.
You may ask, well isn't X tokens worth more readability? Answers is yes, but this is only one function... This starts to add up when you have 50 functions (50x11=550 saved tokens!) and you hit token count and want to finish feature or at least run your game to debug... And saving means that your code will get more and more ugly.
The thing that irritate me, even more than non descriptive code, is the inconsistency in such actions.
I think there is a rule of thumb: if you use some number (especially with operator and variable) more than 3 times it is worth it to put it in separate variable. If you have few operations for one variable, use locals if you use result more than once. If you have even more operations use variables.
Which leads to functions that sometimes have local variables and sometimes don't and sometimes have only some variables for magic numbers...
So what do you think? Is this is me trying use pico8 wrong?
P.S. I understand that pico8 is modelled after old hardware, but do we seriously need to make everything hard because of old times? Embedded code editor, while still pain to use, is reminiscent of old editors and somehow gets modern features to make writing code simpler - why can't this happen with token count as well?
P.P.S. Ability to run game with having more tokens would also allow me to write clean code before I finish everything. Which means I would just refactor code before release. This isn't perfect, but would be good start.