Log In  

I've been hanging out in the IRC channel for a while and it's been really cool to see the community come up around Pico-8. The Fanzine ramped things up by showcasing the cool stuff people have come up with. I haven't made many carts yet but some people expressed interest in what I think makes good code as a professional software developer.

Because of that, I wrote this little series for you guys based off of what I saw in the Fanzine: Clear Code. Some folk in IRC got a kick out of it so hopefully someone here enjoys it as well :)

I also have to say a huge thank you to everyone who contributed to the Fanzine. It takes a certain courage to put your code in public like that so I certainly hope no one minds that I picked some of it apart to make my points.

If you have opinions on code or code snippets to share, post them! I love talking code and Pico-8 brings a lot of interesting developers and ideas together.

P#14505 2015-09-22 18:37 ( Edited 2017-09-27 05:56)

Nice, but I think your recommendations in "Holding state" will cost a lot of tokens. I found in a couple of carts that replacing global tables, like game and player, with a bunch of global variables could save as many as 1000 tokens. That's pretty significant given the 8k limit.

P#14514 2015-09-23 00:15 ( Edited 2015-09-23 04:15)

Yup, one of the problems of using tokens.

playerx += playerdx uses 3 tokens.
player.x += player.dx uses 7.

P#14523 2015-09-23 14:03 ( Edited 2015-09-23 18:03)
:: jcwilk

Yeah, also a professional coder (presumably many/most of the folks here are?) and I think "good code" depends on context, in the pico-8 context one of the chief limiting factors, for better or worse, is that tokens are precious.

Sometimes adding tokens for the sole purpose of improving readability/maintainability/flexibility makes sense, but it's worth noting that with such restrictions, games usually aren't developed long because you can only do so much with it so a lot of those nonfunctional requirements become much less relevant even putting aside the direct implications of the token restrictions.

That's actually the main reason I became a web developer and not a game developer... For the most part, games get written, released, and discarded by the developers. There's little justification for traditionally defined "good code", in fact, most of the time if you wrote everything out very nicely it would be quite bad coding since you spent way more time on it than you should have given the lifespan of the code. I don't enjoy writing and working with bad code so I begrudgingly decided against game development as a career... for now.

Anyways, my point is that I think you have to get a little more clever with your coding suggestions and go beyond general scripting best practices to something that fits in the pico world. Global variables for core objects rather than properties save a ton of tokens, but they don't have to be spread through the whole program indiscriminately... You can still be disciplined about trying to keep certain variables managed by certain functions and make those functions act as abstractions, even though their global functions are technically still available in the global namespace.

function start_animation()
  if animating then
    return false
  else
    animating=true
    return true
  end
end

function animate_attack()
  if start_animation() then
    --initialize variables for the start of the animation
    animating_attack=true
  end
  --do various updates to push the animation along each _update tick
  --eg, adjust global variables for player x and y which will affect code in the _draw function
  px+=3
  if px >= 30 then --usually once it's reached a certain coordinate or global counter or whatever
    animating_attack=false
    animating=false
    px=0
  end
end

function animate_block()
  if start_animation() then
    --initialize variables for the start of the animation
    animating_block=true
    block_counter=0
  end
  --do various updates to push the animation along each _update tick
  --eg, shift through various sprites to be stored in some global variable for the player
  block_counter+=1
  psprite=flr(block_counter/5)%2 --flop between 0 and 1 every 5 ticks
  if block_counter >= 20 then --usually once it's reached a certain coordinate or global counter or whatever
    animating_block=false
    animating=false
    psprite=0
  end
end

function _update()
  if animating_attack
    animate_attack()
  elseif animating_block
    animate_block()
  else
    if btn(4) then
      animate_attack()
    elseif btn(5) then
      animate_block()
    end
  end
end

function display_menu()
  if not animating then
    --code for displaying a menu while not actively animating an action
  end
end

function _draw()
  display_menu()
  spr(psprite,px,py)
end

function _init()
  px=0
  py=30
  psprite=0
  --sometimes i just like to initialize these above the most relevant function in global space
  --but that can get a little dicey
end


I've been playing around with some code like that in a game I'm working on (it has a final fantasy esque battle component, hence the menu displaying and fight/block animations) It's not the prettiest thing and would make me recoil in horror if I saw anything like it at work, however the network of dependencies between each function is pretty minimal (aside from core player variables, it's mostly just one flag being used by one other function for any given function) and there aren't too many more tokens added compared to a more in-lined version, which would be dramatically more difficult to understand.

Just thought it might be a useful example to show code that is mindful and intentional about structure and organization without getting prohibitively expensive with tokens.

P#14540 2015-09-23 17:47 ( Edited 2015-09-23 22:14)

Yup, one of the problems of using tokens.

playerx += playerdx uses 3 tokens.
player.x += player.dx uses 7.

OTOH, if you have a lot of different objects, it might be better to eat the cost of the dot tokens to be able to generalize your movement/collision code.

For a game like Dusk Child where there's only one thing moving, it's right not to waste tokens on a player object.

I wasn't sure if it was a good idea for 8VENTURE, where there are like multiple monsters and objects that can move and interact with each other and I wanted to reuse the collision/drawing routines.

IOW spr(sn,x,y,w,h,fh,fv) is 16N tokens, but draw_sprite(p) is like 36+4N.

P#14543 2015-09-23 20:41 ( Edited 2015-09-24 00:41)
:: JScott

Yeah, also a professional coder (presumably many/most of the folks here are?) and I think "good code" depends on context, in the pico-8 context one of the chief limiting factors, for better or worse, is that tokens are precious.

Absolutely right. Immutability is a hard sell for Pico-8 which is why I made sure to mention that it's a tool to be used appropriately. Does anyone know how the token limit is impacted by splitting up functions? That's certainly an effect of semantic sugar and single responsibility.

games usually aren't developed long

Code lasts beyond a compiled program. Anyone can download your game and pick apart the code to see what it does. Pico-Zine has a huge focus on sharing code and learning by example. You're right that web has a lot more layers upon layers that need refactoring but that isn't to say that there isn't good benefit in games.

I don't know if anyone here plans on collaborating with someone to create a game but that's also another good case for clear code. Musicians might want to place their own SFX calls and modders might want to play with your mechanics, if you're lucky ;)

There would be a bigger benefit if Pico-8 had some sort of packaging system, an easier way to reuse each others' code. That'd be pretty cool. Maybe one day!

(presumably many/most of the folks here are?)

I'm also not so sure about this. I wonder if there's been a poll on the community at all.

P#14545 2015-09-23 23:18 ( Edited 2015-09-24 03:18)

I'm a terrible programmer I pretty much do this stuff as a hobby :Y

P#14759 2015-09-30 12:42 ( Edited 2015-09-30 16:42)
:: JScott

I'm a terrible programmer I pretty much do this stuff as a hobby :Y

You're exactly the reason I wrote these :)

Hobby devs more than anyone need to iterate on code quickly and I think that a lot of these ideas help to do that but come from years of experience. It's easy to start a small hobby game but it's really hard to finish it so you can use every edge you can get.

P#16054 2015-10-31 14:44 ( Edited 2015-10-31 18:44)

I love that refactor of the train example. That if-else re-indentation took me forever even in sublime due to the known sublime3 reindent bug. Thank you for sharing your knowledge (even though I'm 2 years late :)

P#44646 2017-09-26 17:03 ( Edited 2017-09-26 21:03)
:: DR4IG
1

"There would be a bigger benefit if Pico-8 had some sort of packaging system, an easier way to reuse each others' code. That'd be pretty cool. Maybe one day!"

I suggested something akin to extra 'roms' or 'modules' that could be included in the carts (Limited of course or what's to stop people from having their cart consist entirely of ROM extras? :P) Simulating how early developers on limited systems would add extra function roms or cpus directly to the cartridges' boards or the system itself in the case of expansions (From the ol' C64 daughterboards to newer things like the n64 expansion card)

This way someone else has a really nice movement and collision routine, Instead of trying to grok how they did it, Or copy-pasting it into your code (And maybe breaking it because your functions and the OP's differ!) the author of that code could make a 'rom for collision and movement" and you could borrow that for your cart, Leaving you free to deal with the rest of the code you need to write (And not wasting half your tokens on one part of the program.)

P#44648 2017-09-26 20:43 ( Edited 2017-09-27 00:45)

Same here - software professional. On my yet to be released game, I initially went down the route of lua classes and inheritance, to realise later I won't get past the credit screen unless I focus on token count fast!
That said, I kept a couple of self:fn construct for truly generic things.

P#44655 2017-09-27 01:56 ( Edited 2017-09-27 05:56)
:: zlg

Just swinging by to say that I agree with the premise of your articles, but the references to other, less-specific work to answer the "why" and the "how" feels like you're not done with it yet.

It's easy to find general advice on programming that's dry and sparse on details. Most of what you'll find is very generalized, or written from the perspective of an entrenched academic or professional. As a result, it's often difficult to both interpret and practice, because the communication style used is indirect and you're expected to "just get it". It's really easy to learn a new piece of programming knowledge and then start using it everywhere, too; knowing when to use something is also important.

It's less easy to find how concepts and practices from the professional and academic software world can be applied to a fantasy console and make developing games more rewarding. I'm talking about stuff like tightening the feedback loop during development, cementing a programmer's understanding of their tools, or teaching the math concepts needed to render 3-D scenes or animation curves, giving them the conceptual and mechanical models they need to "level up" their game design muscle. In other words, how do you put these concepts to work directly in PICO-8? That's much more relatable to this audience, and can demonstrate the value of smarter design with carefully crafted live PICO-8 demo carts. Additional prose can accompany the carts and explain why something works. It focuses on showing rather than telling, leading to greater understanding.

A great example imo is how closures can be used to encapsulate game states, turning them into first-class data types that can be passed around at will. If your PICO-8 game is complex enough, you're going to need some guarantees regarding state so you can keep things straight in your head. Coming at these concepts from a "Problem -> Solution" angle or even picking on a cart in the wild (hopefully with the author's permission) adds more depth and value to the advice being offered.

If you or someone else ever successfully covers topics in this style, I'd be happy to read it. I'd even pay for it, if it taught me things I could apply to other languages. Still, a push for better code is a push in the right direction so I'm with you in spirit. :)

P#65225 2019-06-15 23:31

[Please log in to post a comment]

About | Contact | Updates | Terms of Use
Follow Lexaloffle:        
Generated 2019-10-24 02:43 | 0.026s | 2097k | Q:34