Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Masters of the Universe

A topic by TheRoboz created Jun 02, 2020 Views: 2,237 Replies: 11
Viewing posts 1 to 11
(3 edits) (+11)

A Barbarian remake for pico-8 but with a Masters of the Universe themed makeover.

Game released! Play it here: https://theroboz.itch.io/motu

(+3)

A little teaser for this project, based on great C-64 pixel art concepts by John Henderson and some tricks learned n the last game-jams.


Next to do: gfx editor to avoid hand-coding backgrounds elements

Looks good!

Lovin the pixel art style!  I'd give that game a go from that one image.

(+4)

Artsy Backgrounds on the cheap

The first obstacles on this project’s development path are backgrounds.

My goal is to have at least 4, maybe 5, full screen painterly-style backgrounds similar to this 128x128 reduction of John’s original background

Grayskull

John's artwork rescaled to 128x128
but pico-8 has some limitations that makes this quite a challenge (as in no real storage space for bitmaps) and every compression solution I found usually eats into sprite memory, which I need 100%.

Other esoteric compression and storage solutions using map memory, sfx memory or encoding sprites in strings  still end up are complicated and, no matter how I tried, a straightforward bitmap compression ended up using over 50% of available resources for a single image while adding a lot of code to handle compression/decompression and swapping, so I had to try a different approach.

this first background has a lot of black areas, some similar “blocks” who lend themselves to tiles plus a pretty handy horizontal symmetry; pico-8 gfx strengths are fast enough graphic primitives, versatile tile map, pattern fills and an interesting  available slot of memory at 0x4300 - 0x5dff which I had no other idea how to use so my idea was to see if I can draw half background using as little tiles as possible and mirror it and then use some trick to mask the symmetry

the following gif shows all the steps that build the final background on pico-8  (the trick is on step-8):


  • 0-clear screen to sky color (top right shows the 20 sprite tiles used for the background, which have a lot of transparency so they can be overlaid on different background colors
  • 1-add a sky gradient with a patterned filled rectangle
  • 2-add black filled rectangles to lay out most of the black area
  • 3-add some colored shape to fill transparent areas behind tiles and main ground area
  • 4-add lighter gradient on ground
  • 5-add one last shadow to be drawn under the tile map
  • 6-the 20 tiles are reused in different locations to build the left half of Grayskull castle
  • 7-cover some blocky edges with a black filled circle
  • 8-Here we flip and draw the left side to the right but we skip the first rows of tiles since the right tower will be shorter, and we offset everything 1 pixel to the left and 1 pixel down to avoid a perfect, visible symmetry in the eyes and dome, then we copy this right half to a small work ram area that can contain at most 75% of a full framebuffer, since the right tower will be shorter anyway This step is only done once, at background switching so the CPU cost of this flip and copy is negligible
  • 9-In the real draw function, called 30 times per second, we only repeat steps 1 to 7 which has little CPU cost, then we just memcopy the pre-rendered right half from work memory to the framebuffer.
  • 10-With draw some of the original tiles, un-flipped over the flipped right area to mask the symmetry and complete the tower
  • 11-Final black dithered pass to add some “noise” details and cover the blocky-ness

We can now add some animating effects, as clouds and mouth glows to make it more alive

Here is the final result:


CPU cost of all this plus existing game code is around 15%, sprite used 20 (some of which I hope to re-use in other backgrounds). This gives me an approachable target of 4 or 5 background in this style while having at least 3 pages of sprites for characters and other gfx items

But now I need a comfortable way to prepare all this shape drawing code which, up to now, was hand-coded as a test.

In the next post I will discuss the custom-made solution and editor I wrote for this

Excellent breakdown and technical use of limitations, looks fantastic.

Rolling your own editor

Disclaimer: this post opinions are based on a very cursory knowledge of the Lua language

After deciding on a mixture of tile-maps and shape-drawn background styles, I needed a tool to quickly and conveniently draw these shapes, because the hand-code experiment of Grayskull was too cumbersome. I just wasn’t sure if I had enough Lua/pico-8 experience to write one.

Seeing other’s editor examples though, the temptation was too strong and I am glad I tried. Writing picoDraw was a lot quicker than I thought, the process gave me a lot of additional good ideas to implement and, most of all, it was fun!

Since the drawing leverages a lot of existing pico-8 commands it was very easy to implement a working prototype, I will just highlight some details found interesting while programming and the unexpected solutions to some of my perceived difficulties:

 1 – parsing and executing commands:

I am a big fan of Casey Muratori’s “write usage first” philosophy:

“you must always, always, ALWAYS start by writing some code as if you were a user trying to do the thing that the API is supposed to do”

https://caseymuratori.com/blog_0024

I worked backward from how I envisioned I was going to use picoDraw’s idealized output, a “stringified” series of command, since I already have code to extract symbol-separated data from a string for other game’s items

 for simplicity I decided on using exactly pico-8 drawing function names and parameters.

cmd_list = “circ,16,16,8,1,rectfill,4,2,8,4,2,map,0,0,8,8,4,6,line,1,1,16,18,7,…”

First bit of luck was that even if gfx functions have different numbers of parameters, turns out the extra parameters are ignored, so for parsing simplicity I decided to store every function with the maximum numbers of params, 6, as in  map(sx,sy,x,y,w,h):

cmd_list = “circ,16,16,8,1,0,0,rectfill,4,2,8,4,2,0,map,0,0,8,8,4,6,line,1,1,16,18,7,0…”

In this way I know each command is a series of 8 comma separated elements.

Now, how am I going to parse this into functions and parameters, in a simple way, so that I can just write something like: 

    draw_list(cmd_list)

I remembered seeing this pico-8 repl cart:

https://www.lexaloffle.com/bbs/?pid=71429 by user @thisismypassword

Which I thought might have some answers and turn out it did, it introduced me to the Lua _ENV variable, where turns out all function names are stored as key/value pairs, so my parsing code was incredibly simple, I just split the string  into a commands table = {{“circ”,16,16,8,1,0,0},{“rectfill”,4,2,8,4,2,0}} which is also the way shapes are stored in memory and then

function draw_list(commands)

    for i=1,#commands do        

        local cmd = commands[i]

        _ENV[cmd[1]](cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7])  

    end

end

 Right off the bat I had real-time drawing of the command list and easy parsing/ of the string output, with no special cases, no convoluted code and not a lot of token use, since this code has to run in the game too, but in game there’s a further optimization for tokens, if when I parse I store the command as the last item in the table, I can then do this:

function draw_list(commands)

    for i=1,#commands do

        local cmd = commands[i]        

        _ENV[cmd[7]](unpack(cmd))        

    end

end

*this code draws the complete left half of the background, map included, leveraging existing pico-8 functions. Then we just flip copy it like I explained in the previous post

As a neat side effects, it is easy to just traverse this list, drawing at each index increment, to have a nice step-by step recreation of your drawing, #putaflipinit style:

*replay of he-man’s portrait drawn by importing an image as a map (hidden here) and using it as an onionskin reference in picoDraw!

*and here is the command list “

 2 – Undo function:

I was worried about implementing an undo function because I thought I was going to have to keep a stack of commands and command inverses (cmd pattern… aaaaargh!!!) or something, but looking at the console output suddenly I thought I could just save a table of cmd_string and just run an index through it, when I reach the desired undo, just parse the current string and purge all the subsequent one, in few minutes I had undo/redo working… now for sure it’s not the most elegant solution and in the long run could have bad side effects on memory but, for the current scope and usage it works pretty well and again, little code and tokens:

function do_undo(d)

    cmd_string = undo[undo_index+d]

    undo_index +=d

    shapes={}

    add_draw_commands(shapes,cmd_string) -–split string into a command table 

end

 3—load/save:

I knew I was going to depend on the clipboard to get the cmd_string in and out of picoDraw and while I was pasting any existing drawing in code and parsing it at init() time, @JohanPeitz showed his awesome 3d editor load/solution and gave me a code tip which made it really trivial to implement ctrl-v pasting at runtime, so now you can save and resume any drawing you want.

if k == 213 then 

     cmd_string,s=””,stat(4)  

for i=1,#s do     --sanitize pasted text

          for c in all(allowed_chars) do 

               if (c == sub(s,i,i))  cmd_string..=sub(s,i,i) break

          end

     end

     shapes={}

     add_draw_commands(shapes,cmd_string)  

else …

Look! It is almost exactly like the undo code!

All these conveniences are bonuses earned from settling on a simple data format following the usage first design (and pico-8/Lua awesomeness!)

4 – fill patterns

I was thinking of a complicated approach to this, storing a different fill command, or generating it when outputting the string but, since all commands except map still have a spare entry, I decided to just stick the eventual fillp there, so when it’s we don’t do anything and when there’s a value we apply it before drawing this shape and clear it afterward (or we can set a bool if we are in a fill or not and just clear once at first 0, this depends if we need more tokens or more speed)

cmd_list = “circ,16,16,8,1,0,0,rectfill,4,2,8,4,2,-512,map,0,0,8,8,4,6,line,1,1,16,18,7,0…” --rectfill now has a pattern applied

for i=1,#commands do

     local cmd = commands[i]

     if (cmd[6]!=0 and cmd[1] !=4) fillp(cmd[6] +.5)  -- base pattern + transparency     

     _ENV[cmd[7]](unpack(cmd))

     fillp()

end

5 – additional ideas:

Granted this tool is still unfinished and rough around the edges but, for a week worth of work, it was a pretty good investment for game assets creation and for personal learning. Now I am implementing some further refinements

Once oval() is available in pico-8, code will be further simplified because all the if else/ to manage circle exception will disappear, since I guess oval will use 4 params as rect and store color at the same parameter position and I won’t have to use giant circles any longer to get large, smooth curves

I think I can write a small triangle function that can fit into the existing data format, to avoid overusing rects for complex shapes, with a minimal token utilization, it should be easy to use in game too.

As you can see in the portrait examples, I switched to numbers as command, to compact output a bit, and I just do one lookup in a command table, now the execution is:

     _ENV[cmd_string[cmd[7]]](unpack(cmd))

Still compact enough

I plan to encode cmd parameters length in this cmd index too, to allow variable length cmds, and save characters while not over-complicating the string splitting

My final goal is to normalize all coordinates and gradients so they can all be written as hex 00-ff allowing to store drawing data in map or sfx space, should the necessity arise

All this will be done after I progress a bit further with the game code. Now back to sprite work and game programming.

 If there’s anything to learn from this post it is: Don’t be afraid to try and roll your own tools, sometimes it’s quicker than wrestling somebody else’s into doing your own bidding. 

picoDraw current stats: 3500 tokens, 23100 chars

WOW. How do I get this Grayskull power?

(+1)

No time for a full post, been busy with sprites and animation. Just a preview of current progress and next time I'll discuss whats happening behind the scenes.


(1 edit) (+1)

Ok, i am too busy programming to write real articles about the game, will probably do some postmortem when it's done. Progress has been good though and here is the complete character roster. If i can squeeze them in i might add 4 more special guests


(+1)

And here is the second teaser

(+1)

Game is complete! You can play it here: 

Masters of the Universe

Sorry for the lack of updates but coding took up more time than I forecasted, hope you all enjoy the game.