Micro Platformer - Simple Platforming Engine in 100 Lines of Code

“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.

I think what @Hanski is suggesting is to bypass the regular hi-res screen drawing which has an image buffer and clears the screen at a regular interval and use a system where individual sprite objects are used instead of a screen buffer and the sprites are drawn directly when the screen needs to update.

I remember him demonstrating this trick but can’t remember which thread.

But @jonne’s mention of dirty rects is another reasonable solution since it avoids the expensive process of clearing the screen.
(Fun fact: the well-known version of ‘Solitaire’ packaged with older versions of Windows achieves the trick with the cards by not clearing the screenbuffer.)

Sprite system is explained here:

When the palette trick is implemented the FPS will be even more!

1 Like

Oh I see! So with this “sprites” technique, I would probably want to limit the game to single screens at a time (like Legend of Zelda) and avoid side-scrolling or anything like that (hopefully the tiled mode come together soon for that kind of thing).

Giving it a go now…

1 Like

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:

3 Likes

Right. For scrolling, I would use 110x88 mode to have a good fps. But sprites do not work in that mode.

Looks great! Cannot wait for the actual graphics update :slight_smile:

But… Old 8-bits had one size fits all, there was no other way. You had a tiled screen mode with a fixed tile size, colour depth and even a fixed max number of tiles. The 8-bit era had many many wonderful games that found ways to get a round or enhance this limitation.

I don’t 100% like the idea of artificial limitations on a console (e.g. pico-8) but I think it might be worth considering in this case.

That was because of hardware limitations.
Old consoles handled tiles and sprites in-hardware,
often with processors acting like the precursor to GPUs (notably the PPU of the NES/SNES).

Things like changing z-order, multiple layers and the like are fine if you need them,
but if you don’t need them and you’d rather have the extra memory/processing,
then there should be a way to make that exchange.

Sensitive on Pokitto does also. :slight_smile:

1 Like

@Hanski: Is there any reason why Sprite mode only works in Hi Res mode? I’m finding the 4 color limit a little… limiting, so I am considering switching to Standard Res, but without Sprite Mode, performance is pretty bad.

Am I doing this right?..

    setTileProvider( []( int x, int y )->int{
        return myMap[ x+32*y ]; // tile id at row Y, column X.
    });

It doesn’t seem to show the correct tiles…