Pablo 101 – Initial screen layouts
Making a simple platform game : Pathetic Pablo Bros : Disastrous Situation
Introduction
This is a simple / small tutorial on how to make a 2D platform game. The game will be based on the Pathetic Pablo Bro’s game for the ZX Spectrum that was first wrote by Steve Anderson for Your Sinclair as a type in game (Dec 1992 – Feb 1993, with the game being on the tape for the March 1992 issue). I will attempt to develop this little game from it’s simple type in information from the magazine to something that the DS can actually play, then drag it into the modern age with better graphics and scrolling levels.
I’ll be assuming that you have the development kit installed, and that you know how to compile a simple hello world nds file.
Graphics
Taking into account that the graphics on the spectrum are very simple (character grids, with only 2 colours allowed) I thought I’d stick to this approach for this document, and a future document will move some of the graphics around and bring them into the 21st century. The design of the game is simple – you have a main character, some walls, a spike and an exit portal for the screen (on the type in game each “level” was actually a screen). So lets get started with these images:
![]()
These are the user defined graphic tiles that are used for Pablo, you might be able to make out the shape for Pablo, but to make things a little cleaner, here he is in all his 16×24 pixel glory:
![]()
The graphics on the spectrum are stored after the normal character font, and that’s what I’m going to do, but first I need a copy of the original font data, which can be found online quite easily. The following image is the entire ZX spectrum font set with the pablo graphics added into the udg area.

Put the above image into your data folder and we will start off on our adventure of development
Main loop
Now because I’m going after a true copy of the ZX Spectrum version of the game initially, I’m going to be doing everything via the console (who said that the console was slow for games?) but with a minor change, I’m not going to use the console iprintf commands to update the screen (I could, but this would cause issues later when I implement other features), I’ll make some of my own functions that will update the tiles. First of all lets get the main loop out the way:
int main( int argc, char *argv[] )
{
initScreen(); // Call to the screen initialisation code
// Initialise the file system so that we can access external files.
if( !nitroFSInit() )
{
iprintf( "Unable to init file system" );
exit( 0 );
}
fLevels = fopen( "levels.dat", "rb" );
initPablo(); // Set up some global variables – these are normally
// bad, but for this little exercise they are good
initStats(); // init the status display
showLevel(); // Show the level
while(1) {
showPablo(); // Put Pablo on the screen
showStats(); // Show the players lives, etc on the screen.
swiWaitForVBlank();
erasePablo(); // Erase Pablo
}
return 0;
}
This is a nice and simple initialisation of the game states and then it enters an infinite loop that shows the current stats panel information (lives, coins and score) and then shows Pablo in the correct position. The file system that I’m initialising here is the nitroFS / libfilesystem one that is provided with libnds and since this filesystem works with one of the emulators (no$gba) then I can test any code on the emulator before running it on a real DS only for it to go bang after a couple of seconds. There’s a couple of changes that need to be done to the makefile to allow libfilesystem to work, these are:
- Add the following to the list of folder names:
- NITRODATA := pablodata
- Adding the libraries into the makefile by changing the following line:
- LIBS := –lnds9
to
- LIBS := -lfilesystem -lfat –lnds9
- Add the following lines to add in the default data files of the game:
- ifneq ($(strip $(NITRODATA)),)
- export NITRO_FILES := $(CURDIR)/$(NITRODATA)
- endif
I put these lines after the export DEPSDIR line.
With these changes to the make file all that is left is to create a folder called pablodata in the root of the game folder.
Level Data
Since the levels on the original ZX spectrum version of Pablo Brothers were saved in data lines and I want to be able to add new features to the game at a later date without much hassle, and also to allow people to design their own levels. So before we get the file loading, we need to work out a simple file format. Initially we can use a text file that uses letters in place of the graphics, but what do we need to put in the file, lets start with listing the tiles we are going to use:
- Wall
- Coin
- Spike
- Exit door
- Pablo’s start position, and direction he is facing
looking at the keyboard’s easily accessible keys, some items can be picked out easily:
- # Wall
- c Coin
- ^ Spike
The exit door is not one tile, but 3 tile, well 2 different tiles actually, so it will need 2 characters, + and | would be good, as they allow you to show the special top of the door tile (+), and then the main part of the door (|).
Pablo’s start position is a little different, since Pablo is 2 tiles wide by 3 tiles high, we could use a single character to show his start position, but how to show direction, and which tile would the Pablo start character be for? A simple approach would be to just put the initialisation data for Pablo in a little section above the level data, so that it’s separate from the level data and can be edited easily enough. With the basic information for a level sorted, lets create a simple level to load into our game:
1,1,> ################################ # # # c# # # ########################### # # # # # # # # ############################ # # # # #c # ##### + # #### | # #### | #####################^##########
The above level is just a couple of floors to walk along, and then a spike to jump, finally the door at the bottom right of the level. There’s a couple of coins to pick up, so the level has every tile type in it, so when we start moving Pablo around we will be able to add the collision code in as well.
Create a levels.dat file and save it to the pablo data folder so that when you transfer the code to the DS you will copy that as well.
DS Screen and global variables setup
Unlike the Spectrum we have to setup the screen, so to do this the following function is used.
//global variables for the game
u16 jump, level, score, coins, lives;
u16 pablo_x, pablo_y, pablo_dir;
u16* mapBG;
FILE *fLevels;
void initScreen()
{
const int tile_base = 0;
const int map_base = 20;
ConsoleFont font;
videoSetMode( MODE_5_2D );
videoSetModeSub( MODE_0_2D );
vramSetBankA( VRAM_A_MAIN_BG_0x06000000 );
vramSetBankC( VRAM_C_SUB_BG_0x06200000 );
// Initialise the console with a custom font
PrintConsole *console = consoleInit(
0, // A pointer to an existing console
0, // Background layer
BgType_Text4bpp, // Background layer type
BgSize_T_256x256, // Background layer size
map_base, // The base of the map data
tile_base, // The base of the tile data
true, // Use the main display
false ); // Load a custom font graphics
font.gfx = (u16*)pablo_fontTiles;
font.pal = (u16*)pablo_fontPal;
font.numChars = 131;
font.numColors = pablo_fontPalLen / 2;
font.bpp = 4;
font.asciiOffset = 32;
font.convertSingleColor = false;
consoleSetFont( console, &font );
// Store the map base for later use
mapBG = console->fontBgMap;
// This is to swap the black and white palette entries in the
// initial font image
BG_PALETTE[ 0 ] ^= BG_PALETTE[ 1 ];
BG_PALETTE[ 1 ] ^= BG_PALETTE[ 0 ];
BG_PALETTE[ 0 ] ^= BG_PALETTE[ 1 ];
}
void initPablo()
{
jump = 0;
level = 1;
score = 0;
coins = 0;
lives = 5;
pablo_x = 0;
pablo_y = 0;
pablo_dir = 0;
}
A wall of code that does nothing much. This is just your basic init code for any DS application – set the screen modes to MODE_5_2D ( basically a 4 layer tile background where layers 2 and 3 can be set to any rotation angle you want). Then we setup the console, on the DS the console is nothing more than a very simple tile engine that uses ANSI codes to place tiles on the screen, with a few limitations on some tile numbers, but there’s nothing wrong with utilising the console as a quick and dirty tile engine, besides it also allows us to use the spectrum font in the console for any error messages. Once the console is setup its then a simple case of loading the font into memory.
The global variables are set to their initial values at the start of a new game – no score, no coins, 5 lives, and level 1. the pablo_? variables are set to 0 as they will be read from the level data file that is read in during the showLevel() function.
Printing the level
Initially in the Spectrum code this was just a case of restoring the data pointer to a specific location in the listing and then reading a string then printing it on the screen. Well we can’t do that (ok we could do that, but we would get the above level data on the screen, not the nice graphics that we want) so we have to deal with the level data one byte at a time.
void showLevel()
{
u8 i;
u8 x, y;
// if this is level 1, then reset the file pointer to the start
if( level == 1 )
fseek( fLevels, 0, SEEK_SET );
// read in the initial position and direction
pablo_x = 0;
i = fgetc( fLevels );
while( i != ',' )
{
pablo_x *= 10;
pablo_x += i - '0';
i = fgetc( fLevels );
}
pablo_y = 0;
i = fgetc( fLevels );
while( i != ',')
{
pablo_y *= 10;
pablo_y += i - '0';
i = fgetc( fLevels );
}
i = fgetc( fLevels );
if( i == '<' )
pablo_dir = -1;
else
pablo_dir = 1;
fgetc( fLevels );
fgetc( fLevels );
for( y = 0; y < 16; y ++ )
{
for( x = 0; x < 32; x ++ )
{
i = fgetc( fLevels );
switch( i )
{
case ' ': // blank space, so put a space
putAt( x, y, ' ' );
break;
case '#': // # = Wall
putAt( x, y, 160 );
break;
case '^': // ^ = spike
putAt( x, y, 162 );
break;
case 'c': // c = coin
putAt( x, y, 127 );
break;
case '+': // + = top of door
putAt( x, y, 161 );
break;
case '|': // | = rest of door
putAt( x, y, ' ' );
break;
}
}
fgetc( fLevels );
fgetc( fLevels );
}
}
The first thing we do is to check if we are working with the first level, and if so reset the file to the start. Next we read the initial values for Pablo, his x, y and direction information is stored as 2 integers and then a bracket to show which way he is pointing. As I’m working on a windows PC I know that the file is saved with a CR+LF to mark an end of line, this is the reason for the dual fgetc() calls that are not returning the read value. The main part of this code just loops around the screen display (32 tiles by 16 tiles) and loads one byte at a time into the screen display, this saves some memory as we do not need to store the map in 2 places at once, and it stops people making malformed levels. This is a simple load and show information on the screen code, if you wanted to extend the map to the right by another screen then this code would need to be re-written, but since Pablo only knows what a small room looks like in his world what we have here works fine. The putAt() function is a macro that is defined at the top of the source file as:
#define putAt( x, y, c ) { mapBG[ ( ( y ) << 5 ) + ( x ) ] = ( ( c ) - 32 ); }
As you can see this macro just puts the correct tile number into the correct map location. The (c)-32 is due to the font not having any images in the first 32 characters so they are not stored in the image.
Displaying the status
This is actually 2 functions here, originally it was one function that cleared the screen, drew the walls, ceiling and floor, and then put the score, lives and coin information in the little status panel at the bottom of the screen. For the DS I split this into 2 functions, one to setup the display panel, and one to put in the current values. Lets start with the screen setup.
void initStats()
{
u8 i;
// Lives display
putAt( 1, 17, 139 );
for( i = 2; i < 12; i ++ )
putAt( i, 17, 131 );
putAt( 12, 17, 135 );
putAt( 1, 18, 138 );
putAt( 4, 18, 'P' );
putAt( 5, 18, 'a' );
putAt( 6, 18, 'b' );
putAt( 7, 18, 'l' );
putAt( 8, 18, 'o' );
putAt( 9, 18, 's' );
putAt( 12, 18, 133 );
putAt( 1, 19, 138 );
putAt( 12, 19, 133 );
putAt( 1, 20, 138 );
putAt( 12, 20, 133 );
putAt( 1, 21, 142 );
for( i = 2; i < 12; i ++ )
putAt( i, 21, 140 );
putAt( 12, 21, 141 );
// Coins display
putAt( 21, 17, 139 );
for( i = 22; i < 26; i ++ )
putAt( i, 17, 131 );
putAt( 26, 17, 135 );
putAt( 21, 18, 138 );
putAt( 22, 18, '$' );
putAt( 26, 18, 133 );
putAt( 21, 19, 142 );
for( i = 22; i < 26; i ++ )
putAt( i, 19, 140 );
putAt( 26, 19, 141 );
// Score display
putAt( 17, 20, 139 );
for( i = 18; i < 30; i ++ )
putAt( i, 20, 131 );
putAt( 30, 20, 135 );
putAt( 17, 21, 138 );
putAt( 18, 21, 'S' );
putAt( 19, 21, 'c' );
putAt( 20, 21, 'o' );
putAt( 21, 21, 'r' );
putAt( 22, 21, 'e' );
putAt( 23, 21, ':' );
putAt( 30, 21, 133 );
putAt( 17, 22, 142 );
for( i = 18; i < 30; i ++ )
putAt( i, 22, 140 );
putAt( 30, 22, 141 );
}
All this function is doing is to put special tiles at specific locations, the status area is split into 3 distinct areas: Lives, Coins and Score.
The code that shows the current status by comparison is very small:
void showStats()
{
u8 i;
u16 tmp;
// Show the current lives
for( i = 2; i <= lives << 1; i += 2 )
{
putAt( i , 19, 144 );
putAt( i + 1, 19, 145 );
putAt( i , 20, 146 );
putAt( i + 1, 20, 147 );
}
// Show the coins collected
tmp = coins;
for( i = 25; i > 22; i -- )
{
putAt( i, 18, '0' + tmp % 10 );
tmp = tmp / 10;
}
// Show the current score
tmp = score;
for( i = 29; i > 24; i -- )
{
putAt( i, 21, '0' + tmp % 10 );
tmp = tmp / 10;
}
}
The lives display is actually using the head of Pablo to add something to the lives display other than another set of numbers. The numerical display for both the coins and the score is created backwards, using a modulus of the value and 10 to get the digit, and then the value is divided by ten to get the next digit ready for display.
Showing and erasing Pablo
Two functions to deal with Pablo on the screen, one to erase him and one to draw him in the correct position. These functions are really placeholders for the time being as in a real DS game you would not be putting the sprite data directly into the map you would have a sprite moving around the map, and you would update the map as and when you need to. Since this is a true as possible to the original remake, I’m using the map as the sprite layer at the same time.
void erasePablo()
{
putAt( pablo_x , pablo_y , 143 );
putAt( pablo_x + 1, pablo_y , 143 );
putAt( pablo_x , pablo_y + 1, 143 );
putAt( pablo_x + 1, pablo_y + 1, 143 );
putAt( pablo_x , pablo_y + 2, 143 );
putAt( pablo_x + 1, pablo_y + 2, 143 );
}
Erasing Pablo is easy, just put 6 spaces where he was standing, displaying Pablo is a little more complex:
void showPablo()
{
if( pablo_dir == 1 )
{
putAt( pablo_x , pablo_y , 144 );
putAt( pablo_x + 1, pablo_y , 145 );
putAt( pablo_x , pablo_y + 1, 146 );
putAt( pablo_x + 1, pablo_y + 1, 147 );
if( ( pablo_x & 1 ) == 0 )
{
putAt( pablo_x , pablo_y + 2, 148 );
putAt( pablo_x + 1, pablo_y + 2, 149 );
}
else
{
putAt( pablo_x , pablo_y + 2, 150 );
putAt( pablo_x + 1, pablo_y + 2, 151 );
}
}
else
{
putAt( pablo_x , pablo_y , 152 );
putAt( pablo_x + 1, pablo_y , 153 );
putAt( pablo_x , pablo_y + 1, 154 );
putAt( pablo_x + 1, pablo_y + 1, 155 );
if( ( pablo_x & 1 ) == 0 )
{
putAt( pablo_x , pablo_y + 2, 156 );
putAt( pablo_x + 1, pablo_y + 2, 157 );
}
else
{
putAt( pablo_x , pablo_y + 2, 158 );
putAt( pablo_x + 1, pablo_y + 2, 159 );
}
}
}
Since we are using tiles to store the image data for Pablo and we are changing the map data directly we need to have all the images available in the tile map. Doing this in this way is using 16 tiles, if we were to use sprites, we could get away with a 16x16 and a 16x8 and just swap the 16x8 between 2 sets of data, thus only using 8 tiles (half the amount we are currently using). We could emulate this in Pablo using the tile modes HFlip bit, but that is a little advanced for the current scope of this tutorial and will be covered in a later part of the series.

The image above contains all 4 frames of the animation of Pablo, 2 frames walking left, and two frames walking right. As the only part of the animation that changes is the feet you do not need to save the second copy of the head, thus saving 4 bytes per direction. If you are using the DS’s sprite engine to display the above sprite sheet you would only need the first 2 frames, and you would have to use a 16x32 grid for the sprite, and when Pablo walks left you just set the HFlip bit to flip the animation around.
End of part 1
This is the end of this part of the tutorial series. One thing to do before we move on would be to put some colours into the tiles, which would take the output of the above code from this:
to 
There is also a couple of code edits to make the above changes:
- In the initScreen() function, remove the palette swapping lines.
- In showLevel() change the tile number that is displayed from the current value (‘ ‘) to 143 (which is the tile number of the solid square)
I think you’ll agree that the re-coloured level is a lot better than the black and white version.
Conclusion
Well this is a long page to read – and I need to work out how to cut pages down to a better size – but with the amount of information that is here the first part of a quick and dirty game is worked out. In the next part we will be dealing with movement of Pablo, and collecting coins. With the basics laid out in this series (the 1XX series that is) I will be creating a DS version of the original Pablo Brothers, with all the bells and whistles of the spectrum version. I do have plans for a follow on series that takes this Pathetic Pablo Brothers into something that would look good on a DS, albeit with programmer graphics.
Downloads
Here’s the files for the version of Pablo with coloured graphics, if you want the original black and white version then download the font image from above, clip off the unused tiles above and below and save it over the font file in this version (oh and revert the changes from above).