Micro Platformer - Simple Platforming Engine in 100 Lines of Code

I am going to try and port my “Micro Platfomer” project from Pico-8 to Pikitto, and thought I would document the process a bit here!

About

The goal of this game is to demonstrate a very basic platforming engine in under 100 lines of code (comments don’t count), while still maintaining an organized and documented game.

It is not meant to be a demo of doing as much as possible, in as little code as possible (a la demo scene). The 100 line limit is just meant to encourage people that “Hey, you can make a game with very little coding!”

This will hopefully give new users a simple and easy to understand starting point for their own platforming games.

Note: Collision routine is based on Super Mario Bros 2 and M.C. Kids, where we use collision points rather than a box. this has some interesting bugs but if it was good enough for miyamoto, its good enough for me!

Update 1: After a lot of reading, and jumping around these forums I think I finally understand how Pokitto development works! :worried:

I have decided that I will develop the project in Code Blocks using the Pokitto Simulator, and deploy real builds to my Pokitto every so often to make sure things are work.

Update 2: I create a new build target in Code Blocks, and ported most of the code to C++.

I had actually already ported this project to C# for another project I am working on, Mono8, so porting it to C++ was pretty easy. However, I did disable all of the Level and Rendering logic for the time being, since it will be quite different.

The player simply renders as a white rectangle right now.

Update 3: Simulation is now fully operational. Need to figure out how to get this running at 60fps on actual hardware, and then time to add sprites!

Video of it running on hardware: https://twitter.com/matthughson/status/1003167756420710401

Update 4:

Game is now running at 50FPS on Pokitto Hardware by using the “sprites” technique outlined here:

You can see a video of it running on hardware here:

10 Likes

I am really looking forward to this, just because I know pico-8, so hopefully by comparing the code in c++ and p8 lua I will be able to finally write something for pokitto :smiley:

So far it has been significantly more challenging :expressionless:

There is a lot more work to get things up and running, and a lot random places to look for information. Documentation on the API is pretty sparse too (all the functions are in the API section but with very little context about what they do).

1 Like

I agree, it would be helpful to have examples or better explanitions under the Api item.

1 Like

Just in time! My next game is going to be a platformer, I think I’ll wait a little bit and see how much I can steal er, learn from your code. It’s always a pain to start over with a basic engine every single time.
This sort of tutorial will really help people new to coding, platformers are the backbone of any game system!

I have been intending to re-code ‘Joe’ for Pokitto… https://twitter.com/Spinal_Cord/status/841560461355175937/video/1
This just might be the tipping point to get me to do it!

4 Likes

Looks like a fun game :slight_smile:

That games looks great @spinal! Not sure how much you’ll get out of my Micro Platformer, as it is super basic. But I’ll be happy if it help!

@mhughson I am removing the [Game] tag as that is only intended for projects that have downloadable binaries

Try to get ahead with this so that we can get to try it out for real!

2 Likes

Update 3: Simulation is now fully operational. Need to figure out how to get this running at 60fps on actual hardware, and then time to add sprites!

Video of it running on hardware: https://twitter.com/matthughson/status/1003167756420710401

3 Likes

You definitely need the tiled mode to get this running at your required level of fps.

I will try to get involved and let’s hope @FManga chips in as well

Also, @mhughson, is it necessary to use hires ?

Is there any documentation on this? I can’t seem to find anything but random posts here and there, and I’m not sure they are all talking about the same “tiled mode”.

2 Likes

“Tiled mode” at the moment does not exist in a meaningful way. Many people have been trying different things, for example @adekto, @hanski and @fmanga have done things that relate to it.

Tiled mode requires a different approach to the normal screenbuffer mode, where every pixel is mapped.

I would like to invite @adekto, @hanski, @fmanga, @spinal and @pharap to join the conversation.

We should specify exactly how the tiled mode would be best to implement (size of tiles, color depth, sprite layer etc). After that making the actual graphics mode should be very straightforward.

1 Like

I get the feeling that having all the graphics modes in the PokittoLib makes it harder to maintain and make new modes. Instead, PokittoLib could provide a bare hardware abstraction, maybe just one graphics mode, and the other modes would be libs that built on top of that.


As for tile modes, API-wise, this is what I have in the lib used by Aquarium256:

  void setTileImage( unsigned char id, const unsigned char *tile );

  extern int cameraOffsetX, cameraOffsetY;

  typedef int (*TileProvider)( int x, int y );
  void setTileProvider( TileProvider tp );

First you use setTileImage to associate an id with a 16x16, 8-bit bitmap:
setTileImage( 0, bitmap ); // render bitmap for tile 0

To move the camera, simply set cameraOffsetX and cameraOffsetY.

A 15x12 grid of 16x16 tiles is managed automatically. When the camera moves, all the tiles are shifted within the grid and any missing tiles are requested from the tileProvider. This makes it easy to stream map data from the SD card to RAM or generate tiles procedurally, and you can mask away other data before sending it to the renderer. If the camera moves one column to the right, the tileProvider is called for each tile on the rightmost column.

Say you use 8-bits per cell, where the lower 4 bits are the tile Id and the upper bits are for things like collision detection. You can define a tileProvider like this:

const unsigned char level1[][] = {...};
const unsigned char levelMask = 0x0F; // upper nibble for extra stuff
setTileProvider( []( int x, int y )->int{
    return level1[ y ][ x ] & tileMask; // tile id at row Y, column X.
});

To create sprites and tiles, I drop a PNG and a PAL file into a converter.

Sprites can have any size and are rendered using the blit( x, y, sprite, BlitOp ); function. BlitOp can be NORMAL or FLIP_HORIZONTAL. I didn’t do FLIP_VERTICAL yet.
Since sprites are generally not square, I don’t store them as square bitmaps. This helps decrease space use and it’s faster to render because it does not have to do transparency tests.

/*
----------------
----------------
----------------
----------------
---------   ----
-------     ----
--  --######----
-   ##########--
-   ###########-
-#   ##   ####--
------ #####----
-------  #------
----------------
----------------
----------------
----------------
*/

const unsigned char fish8_sprite8[] = {
//width, height
16,16,

// 16x { offset, length }
0,0,7,3,6,4,6,4,7,3,7,3,6,5,5,7,5,7,4,8,4,7,4,7,7,3,7,3,8,1,0,0,

0x1d,0x1d,0x3e,
0x1d,0x1d,0x1d,0x1d,
0x1d,0x1d,0x1d,0x1d,
0x35,0x2a,0x3f,
0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x1d,
0x1d,0x2a,0x2a,0x2a,0x1d,0x2a,0x1d,
0x1d,0x2a,0x2a,0x2a,0x1d,0x2a,0x1d,
0x1d,0x1d,0x2a,0x36,0x2b,0x1d,0x2a,0x46,
0x1d,0x1d,0x2b,0x2b,0x2b,0x2b,0x2b,
0x1d,0x1d,0x2b,0x2b,0x2b,0x2b,0x2b,
0x2b,0x2b,0x2b,
0x2b,0x2b,0x2b,
0x2b
};

I agree, the multiple screen modes does seem to be getting a bit complicated.
Bare bones I think there should be only a few, perhaps a tiled mode a bitmap mode, then maybe have them both have a full and half resolution option?

As for the tile mode questions. In my opinion, 8x8 would probably be easiest for people to work with, especially when converting projects from other systems. It is a very traditional size to use. Also I think the option to flip the tiles both horizontally and vertically would be a nice option.
256 colours I think gives enough freedom to users, plus it seems to be helpful in rendering the aquarium demo at a good speed.
As for sprites, I think however many can be used without much slowdown would be fine. Perhaps 16x16 again with the same 256 colours as the tile map.

Fantasy Options - I don’t know how easy this would be but…
Sprites having render priority settings over each other and background, allowing them to change z-order between other sprites and even background tiles.
Multiple tile layers? would say 2 layers effect the render time much in a negative way? (just a dream that one).

Plus would make the choice of pixel tools pretty straightforward

1 Like

If you want to use 220x176 resolution, you could use sprites. That would give you a good FPS (starting from 50 fps for one sprite on screen), more than 4-colors on screen and automatic handling of flickering and dirty rects. There is a sprite example in PokittoLib.

1 Like

I second this.

At the very least, they should be separated into different classes/namespaces.

Having different libraries with different APIs would be another good alternative.

Treating display modes as ‘plugins’ or libraries in their own right rather than trying to maintain them as part of the actual library would help to reduce complexity.

It would allow people to choose what they want based on their needs (simple interface vs something for power users).


Though I also still like the suggestion I made a while back about facilitating display modes via template classes:


@spinal the different (and slightly conflicting) suggestions you mention are precisely why we should have multiple options rather than a single canonical tile mode.

If we did have a single canonical tile mode, I think it should be aimed at being the simplest or most general tile mode rather than trying to include features that only certain games will use.
Specialist options should be for specialist libraries because ‘one size fits all’ is nearly impossible in programming.

Features and speed/memory are inversely proportionate,
and are thus conflicting requirements :P

Already now, my ability to mix and match the Arduboy/Gamebuino stuff is mainly limited not by hardware but the complexity of having several libs with overlapping functionality

Abstracting the lowest layer as per your and @FManga 's suggestion makes a lot of sense

If someone wants to make a suggestion (preferably an hand drawn sketch) of how they think the core API / extended libs should be abstracted, I’d be very, very happy

1 Like

Is that true? As I mentioned earlier: an empty hi-res app runs at 19fps with nothing on the screen. But maybe I’m missing something?

@Hanski’s “dirty-rectangle” trick is an old old trick and works. In dirty rectangle, only the “changed” part of the lcd is updated. Easily 40fps in your case.

sprites.bin (48.6 KB)

Also, I’d like to point out, that one of the things that is slowing the hires down significantly, is the indexing of the palette where each pixel value needs to me masked and bitshifted. @FManga already found a solution to that problem by unpacking the palette into unused RAM.