Blog

Seven Day Robotron+

Robotron is one of the finest videogames ever produced. I’ll accept no argument on that score.

So of course, back when we did the Eugenius issue of Way of the Rodent (we’re not dead, we’re just sleeping) celebrating the highs and very highs of the career of Eugene Jarvis, I foolishly thought it would be a jolly idea to try and write a clone of Robotron for the NGPC in a week. It was originally intended to a) allow me to waffle on about the game for a bit as well as b) give me something to aim at on the NGPC and c) show some “props” to the original developers (or for that matter anyone who ever actually manages to finish a game)

Anyway, that version of the game has been available for ages on various sites now, and, well, it’s a bit basic.

SevenDayRobotron

There’s a lot of the DNA of Robotron in there, the grunts zone in on the player, the family are all present and intact, and the base mechanisms for the game are largely there, but it was never going to set the world on fire like that.

But those 7 days weren’t the end of Robotron on the NGPC. I carried on developing it for a while as and when I could, and well, when I found my source code recently there it was. So, I thought it was about time I “finished” it. It’s not perfect, far from it, but it is functionally complete, playable and available for public download for the first time.

RobotronFirstWave

A little bit better, I hope you agree…

After sitting through the tutorial, I thought it would be worth having a deep-dive into a completed game. So, the full source is available on the download link at the bottom of the article.

I won’t bore you with a full code listing here, but a few things to watch out for.

Firstly main.c is not the main program. This “merely” contains the bootstrap and a relatively light loop which mainly checks for game over and level progression.

The main game logic is all held within robotron.c/h. All game objects are encapsulated in a series of structures:

  • Sprite
    • Generic sprite structure, shared between player, shots, family and the Robotrons
    • Laser, extends the generic sprite structure for the player’s shots
    • Player, extends the sprite for information about the player, including score and shot counters
    • Robotron, extends the sprite for information about your enemies, the evil Robotrons
  • Level, includes all enemy information for the current level
  • Game, contains meta information and parameters about the game itself

These objects are created as variables in rtDrawLogo(), rtCreateLevel() and rtCreatePlayer()

The Player, including all input and shot collision detection is handled in rtMovePlayer()

All Robotron movement, including the human family is handled by rtMoveRobotrons(). This branches out to enemy-type specific routines such as rtMoveGrunt(), rtMoveHlk() etc where applicable. Some of the individual robotron movements aren’t fully realised yet (Brains are a bit stupid, and Progs don’t want to move for some reason, so I’m still working on those)

All collisions between the Robotrons, Human Family and the player are handled in rtRobotronCollision(). This is probably the single piece of code that needs a little bit of explanation… Basically, I wanted to lock the game to as close to the VBLANK() as possible and there are a lot of potential collisions in Robotron:

  • Collisions between a shot and the Robotron
  • Collisions between a Robotron and the player
  • Collisions between certain Robotrons (Hulks and Brains) and the Last Human Family

The first two of these are pretty straightforward and relatively limited (one player, four or five shots at most) so even with a brute force collision method of testing every Robotron on screen against them you’ll only be spending a relatively consistent 300 distinct tests to figure out whether you’ve hit something.

The problem comes when you try and test Robotrons against the Family (or against each other in the cast of Electrodes) – there can be as many as 50 of these that need to be tested against each other – so at worst we could have 25×25=625 distinct brute force “have ‘these two’ things collided” tests.

So, what we do is to lock the collision detection into a single VBLANK, and attempt to pick up the collision detection loop on the next blank if we haven’t quite got round to it. It appears to work.

The controls also need a bit of explaining – unlike the arcade original, which requires a twin-joystick that the NGPC simply doesn’t have, the game will auto-fire. You move using the joystick and rotate the angle of fire by 45 degrees clockwise or counter-clockwise using the A and B buttons.

This is still a work in progress, but it’s playable, mostly functional and generally feels quite like Robotron. Which considering the limitations of the NGPC (specifically with the controls) I’m quite pleased with. Full source is available here and if you just want to play the game in an emulator of your choice you can grab it from here

Advertisements

Sounds like Teen Spirit

If you have been playing along with this tutorial-of-sorts you will now be in a position to display backgrounds, create and manipulate sprites, deal with input and create your own graphics. You’re now more than halfway to having all the tools you need to write your own games.

But it’s a bit quiet isn’t it? After all, what is a game without some kind of noise.

There are, at a very broad level, three ways of generating noise from the NGPC for the hobbyist programmer:

  • Direct manipulation of the sound driver
  • 8 Bit Sampled Sound Effects
  • Background Music

I’ll get the first one out of the way before we get much further into this. I am not the person to explain the intricacies of direct sound manipulation, but a bit of trial and error will get you some quite satisfying bells, zaps and whistles.

The direct sound manipulation is built into the framework using the following functions:

  • InstallSoundDriver() – just include a call to this in your code just after InitNGPC()
  • InstallSounds() – provide an array of sound structures to the driver
  • PlaySound() – plays one of the previously provided sounds

The complication here is in InstallSounds(), you’ll need to create an array of sound effects using the SOUNDEFFECT structure from library.h as follows:

  • Channel
  • Length
  • Repeat
  • InitialTone
  • ToneStep
  • ToneSpeed
  • ToneOWB
  • ToneLowerLimit
  • ToneUpperLimit
  • InitialVol
  • VolStep
  • VolSpeed
  • VolOWB
  • VolLowerLimit
  • VolUpperLimit

If you understand what all this means, then you’re already ahead of me. But basically, by changing the parameters (specifically the tone ones) you can manipulate the sound engine to produce a variety of squawks, beeps and buzzes. In my experience, keep it short and you can’t go far wrong.

As a starter for ten, this code allows you to use two different sound effects by pushing the A or B buttons.

enum
{
 SND_SIREN = 1,
 SND_CHIRP = 2,
 NUM_SOUNDS = SND_CHIRP
};

const SOUNDEFFECT Sounds[NUM_SOUNDS] =
{
 { 2, 0x60, 0, 0x60, 0x08, 0x01, 0x02, 0x40, 0x80, 0x0f, 0,0,0,0,0 }, // SND_SIREN
 { 1, 0x40, 0, 0x80, 0x20, 0x01, 0x01, 0x44, 0x82, 0x0f, 0,0,0,0,0 } //SND_CHIRP
};

void main()
{
 InitNGPC();

 InstallSoundDriver();
 InstallSounds(Sounds, NUM_SOUNDS);

 while(1)   
 {
  if (JOYPAD & J_A) // if A is pressed play the siren sound 
   PlaySound(SND_SIREN);
  if (JOYPAD & J_B) // if B is pressed play the chirp sound 
   PlaySound(SND_CHIRP);
  while(JOYPAD); // wait for button release   
 }
}

You can experiment with those values as you see fit to get quite a decent library of sound effects. I use a small custom ROM to play with the sounds and simply keep a note of ones I like.

Sampled sound effects are the next easiest way to get your NGPC to make a sound, and much easier to get “complex” sound effects. You’ll need a couple of external tools to get the best out of them, but this is pretty easy. The basic steps are:

  • Create/Copy/Steal an 8x8x8 (bits/KHz/Channels) .WAV file
  • Run it through wav2c.exe (available here)
  • #include it in your code
  • Call SysPlayWave()

I’m not sure whether SysPlayWave() ever made it into the framework, nor whether it has simply been replaced by some of the undoubtably more complete sound code, but for now we can get our machine to play a sample by adding SYSTEM.LIB to your makefile and including the following snippet in library.c (and create the relevant definition in library.h)

// SysPlayWave
// u8 wave[];
void SysPlayWave(u8 *wave)
{
 __asm(" extern large WAVE_OUT");
 __asm(" ld xwa,(XSP+0x4)");
 __asm(" ld xhl3,xwa");
 //__asm(" ldl xhl3,_wave");
 __asm(" ldb ra3,1");
 __asm(" calr WAVE_OUT");
}

What does all that do?  Ah, well, you know that Arthur C Clarke quote about science and magic? This definitely falls on the side of Magic for me… Suffice to say, if you have sacrificed the chickens in the right order, the NGPC will make a reasonable stab at outputting your .wav file.

Be warned though. This is best suited for extremely short sounds – much less than a second – as it locks the NGPC out of all other processing while the sound plays and is strictly one sample at a time. Just keep that in mind before thinking that you can create a cacophonous noise by overlaying samples. It’s very handy for game over noises and the like though.

The third, and most complex, way to get sound is to use Ivan Macintosh’s NeoTracker plugin. This is brilliant for background music but does require a base level of musical know-how (or in my case, you can find a friend!)

I won’t go into the intricacies of using the Tracker itself (it’s available on the download link here) but similarly to NeoTile, exporting a track essentially creates a C header file. You’ll need to include this in your main.c and then you can call it as follows.

#include "Neotracker_Music.h"

void main()
{
 InitNGPC();
 NeoTracker_InstallDriver();
 NeoTracker_InstallDriver();
 // Music_Data and Music_Len constants will be in the
 // exported NeoTracker.h file
 NeoTracker_SendGroup(Music_Data, Music_Len);
 // BGM_MUSIC will also be as exported by NeoTracker
 NeoTracker_PlayMusic(BGM_MUSIC);
 // Your normal code here
 NeoTracker_StopAll();
}

Now, my musical ability is, if anything, even further down the tree than my artistic skill, but luckily NeoTracker has the ability to import .mod files with very little fuss.

Also be aware that NeoTracker and the library sound functions are mutually exclusive as they both sit in the same part of the NGPC – you can have both running in the same code, but you will have to initialise each independently as you use them. It took me longer than I’d like to admit to work that out.

And with that… this series of tutorials comes to a halt. There’s a lot more that I haven’t gone into in any detail, but with the last half dozen posts you should have enough information available to have a crack at doing something yourself. I haven’t tried to turn you into a programmer as there are already more and better general C coding tutorials available that will help you fill in the gaps. Experiment, steal my code if it helps, and try to turn it into your own thing. Most of all, have fun doing it.

I would like to personally thank the giants of the NGPC development world, who’s shoulders I merely stand on, so in no particular order thanks go out to Flavor, Thor, Ivan Macintosh, Judge, Steve Robb,  Jim Bagley, Loic Julien, Dark Fader, Jeff Frohwein and every other bugger whose hard work I have shamelessly ripped off over the years.

If you want to try any of this on real hardware, your best bet is to get in touch with Flavor over at the flashmasta website. Ed is heavily focused on the awesome Raspberry Pi based GPA project, but is still producing both NGPC and Wonderswan flash cartridges.

Good luck and happy coding. Let me know how you get on…

Stay tuned, I’ll be unveiling some of my projects over the coming weeks…

I’ll get you my pretty

So far, we have kept things pretty simple in terms of graphics. Text and ASCII graphics can get you quite a long way if you’re writing an old-school Rogue-like, but if you’re a Neo-Geo fan, you probably appreciate the pixels.

We’ve skirted around discussions of Tiles in the NGPC, concentrating instead on Palettes and Sprites and so forth. As we have mentioned in passing, NGPC graphics are basically formed from a Tile Set – basically 256 four colour 8×8 pixel graphic blocks. The default installed tile set for the NGPC is a classic ASCII character set. Which is why PrintString() and PrintDecimal() actually work.

Before we really get into looking at how to create your graphics, it’s worth familiarising yourself with the ASCII character set – while you are at liberty to just trounce all over it and put your sprite graphics anywhere you like it is still very useful to be able to fall back on PrintString() and PrintDecimal() to display some basic information to the player.

asciichart.png

This is actually from Excel, so some of these are going to be different to the NGPC tiles for the character, but the fundamentals of ASCII are the same regardless of where they come from. That’s why it’s a “standard” – anyway, very interesting I’m sure you agree. What does this mean to the NGPC developer? If you notice, the normal alphabet, numbers and punctuation are essentially grouped together between position 32 and position 127 of the chart, so as a basic rule of thumb, it is generally best to keep clear of ASCII values 32 through to 127 (or even 0 to 127) when you’re loading your tiles. More on that later. This gives you between 128 and 160 tiles that are “free” for you to do your own thing. If you really do need more, then I’ll assume that you know what you’re doing and you’ll figure out your own strategy for slipping tiles into the gaps…

Okay, lecture over – on to the fun part…

While you are free to do this long hand if you really must, it’s much easier to use a tile editor to create the graphics. I use NeoTile (available on my onedrive here) which although basic, does do the job well.

When you run NeoTile and create a new tileset, spend a couple of minutes setting up the palette to be (at least) similar to the one you want to use on the NGPC itself – it will make your life easier. Click on the palette button and choose the colours you want to use.

To do this, choose Tools/Options from the main menu and set your colours in the dialog:

neotilecolours

Now to create your first tile – in the Neo Tile project window, select Group and New Group from the menu (or press Ctrl-G)

neotilenewgroup

You now have a single tile to work with – use the mouse to draw your masterpiece. You can choose palette colours in the main toolbar and just point and click to draw.

neotileface

You can continue to do this to create any number of tiles

neotilefaces

At this point, you’ll realise why most of my games feature graphics wholeheartedly stolen from other sources. I hope you’re a better artist than I am…

You can also group tiles together to create larger logo or larger sprite tiles if you need too. Be warned, all tile groups in the same project need to be the same size, so if you create a 2×2 group then all the tiles in that tileset will be 2×2 etc. However, it is easier to work with larger canvases if you are doing more intricate backgrounds.

You may also find it useful here to rename each tile group to give it a descriptive name. Simply select the tile group and hit F2 (or select Rename from the popup menu)

neotilenamedfacespng

So far so good, but none of this is getting the graphics any closer to the NGPC display – now comes the un part – from the NeoTile menfu choose File and then Export and save the resulting .c file into your project directory. You should then end up with a file that looks quite a bit like this:

// Exported by NeoTile
const unsigned short Faces[3][8] =
{
    {0x3ffc, 0xdff4, 0x67d9, 0xdff7, 0xfd7f, 0xffff, 0x1ff4, 0x0550}, // Happy
    {0x3ffc, 0x3ffc, 0x57d5, 0xffff, 0xfd7f, 0xffff, 0x355c, 0x1004}, // Sad
    {0x3ffc, 0x3ff4, 0x57d9, 0xfff7, 0xfd7f, 0xffff, 0x1554, 0x0550} // Flirty
};

enum
{
    Happy = 0,
    Sad = 1,
    Flirty = 2
};

Now you’ll see from here why we bothered naming the tile groups as we can now use the enum in code to reference the tile position in the array. But how do we use this?

In our main.c file we simply #include the new tileset.c file like so:
#include "faces.c"
As it stands that has just given us an array of incomprehensible numbers hasn’t it? Well, yes, although the numbers aren’t really that obtuse – again, I leave the exercise of understanding what they mean to the reader.
Regardless, in order to use it, we need to install the array into tile memory.  To do this, there are two functions in the framework – InstallTileSet() and InstallTileSetAt(). Remember earlier when I suggested that you avoid overwriting the lower end of the ASCII chart? Well InstallTileSet() will start at position zero and simply blat the array over the default system tiles. Handy if you really do just want to replace all 256 tiles in memory, not so much if you just want to install three artistically challenged smiley faces, or indeed if you wanted to put more than one set of tiles at a time, so you would tend to use InstallTileSetAt() to put our lovely hand-crafted new graphics starting at position 128 like so:
InstallTileSetAt(Faces, sizeof(Faces)/2, 128);
InstallTileSetAt(Hands, sizeof(Hands)/2, 132);
InstallTileSetAt(Feet, sizeof(Feet)/2, 136);
We can then reference any of our custom tiles in SetSprite() or PutTile() by using 128 + Happy, 128 + Sad or 128 + Flirty. Like so:
SetSprite(iSprite, 128 + Flirty, 0, iXpos, iYpos, 0);

Or even better, adjust the definitions of Happy, Sad and Flirty to start at 128… Also, don’t forget to set your palettes to match the colours you have carefully chosen in NeoTile…

Next time… Have you noticed how quiet it is in here?

Time to take control

So far, we have concentrated on output – so you should now be comfortable with controlling the screen and creating and moving sprites around on the display. Fine for demos or exposition, but we’re not writing a presentation here, this is a game console. And what use is a game console without being able to interact with it.

The NGPC, as you should know if you’ve got this far, has a joystick, two action buttons and an option/start button. Compared to modern games consoles, it’s all a bit basic, but actually that makes your life as a developer a lot simpler. You only basically have seven inputs to deal with. No shoulder buttons, no touch screens, no analog controllers, just a joystick and three buttons.

In short, player interaction with the NGPC is pretty simple – it’s all exposed via the JOYPAD structure. This is simply an unsigned byte which contains a number – you can examine this with the following code – if you ran this and moved the joystick around you’ll see the numbers changing as you press buttons:

void main()
{
InitNGPC();
SysSetSystemFont();
ClearScreen(SCR_1_PLANE);
ClearScreen(SCR_2_PLANE);
SetBackgroundColour(RGB(0, 0, 0));
SetPalette(SCR_1_PLANE, 0, 0, 0, 0, RGB(15,15,15));

while(1)
{
 PrintDecimal(SCR_1_PLANE, 0, 4, 9, JOYPAD, 8);
} // never fall out of main!!!
}

These numbers equate to the contols as per the below image:

ngpcbuttons

So, if you press the joystick UP you should see the number change to 1, down becomes 2, left is 4, right is 8 etc. The fun begins if you press buttons together, if you press UP and button A, or move the joystick in a diagonal then you’ll see 3, or 9 or 17.

All this means is that the numbers are adding up – in coding terms, it’s a bitmap mask. Lets look at it a different way

NGPCButtonTable

These numbers can be added up – so if you press UP and A, you will get 0x11, UP, A & B all together would give you 0x31 etc. Importantly, you cannot get the same result by adding up different buttons (so 0x31 can ONLY be obtained by Up+A+B etc). Even it was possible to push every button simultaneously you would still get a unique code – 0xFF if you care. Okay smartase, it is possible, but only in emulation. Try it if you like.

So, how to deal with in code. That sort of depends on which kind of game you’re writing – at the most basic level, you probably want to move your “player” sprite around the screen using the joystick and use the A and B buttons to fire or jump or do some other actions.

The most basic way of dealing with input then is to use a binary AND (or &) operation and to check the JOYPAD structure against that, like the below snippet:

    if (JOYPAD & J_UP) 
    {
        iYpos--;
    }
    if (JOYPAD & J_DOWN)
    {
        iYpos++;
    }
    if (JOYPAD & J_LEFT)
    {
        iXpos--;
    }
    if (JOYPAD & J_RIGHT)
    {
        iXpos++;
    }
    if (JOYPAD & J_A)
    {
        PRINTSTRING(SCR_1_PLANE, 0, 4, 9, "FIRE");
    }

    if (JOYPAD & J_B)
    {
        PRINTSTRING(SCR_1_PLANE, 0, 4, 9, "BOMB");
    }

This would get you running, but there’s a few things you might – depending on the style of game you’re writing – need to keep an eye on. For instance, if you implement the above exactly as described, then your player would potentially be able to “fire” 60 times a second. Pretty neat, but could cause you problems. So, you might need to watch for the player releasing the button rather than pressing it, or check for a “first press”, or put a timer in place or… One way of doing this that I often use is to copy the JOYPAD structure and then compare the previous state with the current state – a bit like this:

    if (JOYPAD & J_A && !(prevJOYPAD & J_A))
    {
        PRINTSTRING(SCR_1_PLANE, 0, 4, 9, "FIRE");
    }

    if (JOYPAD & J_B && !(prevJOYPAD & J_B))
    {
        PRINTSTRING(SCR_1_PLANE, 0, 4, 9, "BOMB");
    }

    prevJOYPAD = JOYPAD;

 

The exact method you choose to deal with inputs is up to you, and even with only four directions and three action buttons, you still have lots of options – you might want to initiate a timer when one combination is pressed and give the player a time limit to get to the next combination for a sequence, you might indirectly control the player object with a velocity or power gauge rather than directly control the position. There really isn’t a “right” way to deal with input, as it all depends on what kind of game you’re writing… An RPG is different to a shooter is different to a card game is different to an RTS etc, but this should get you moving. Literally.
Next time. Make it pretty…

And so it moves…

We all know what a sprite is don’t we? It’s kind of built-in as part of our base language – a bit like asking what is a cloud, or what is love? A sprite is our window into the world of the game the player, the enemies, little incidental touches in the background. In short, things that move about, but what exactly does that mean in programming terms on the NGPC?

If you remember our previous discussion, we can imagine the NGPC graphcis as having two tile planes which contain background images and a third sprite plane which sort of sits on top of those and is used for, yes, moving stuff around.

NGPCScreenPlanes

A NGPC sprite is therefore, one of 64 single tiles which sits on this sprite plane. Each sprite has:

  • an identifier
  • a depth indicator
  • a chain indicator
  • a position
  • a palette
  • a tile number

So, if we put all of that together we can pop a sprite on screen quite quickly

void main()
{
   u8 iSprite;
   u8 iXpos;
   u8 iYpos;
   InitNGPC();
   SysSetSystemFont();
   // TODO: add game code - and remove hello world :-)
   ClearScreen(SCR_1_PLANE);
   ClearScreen(SCR_2_PLANE);
   SetBackgroundColour(RGB(0,0, 0));
   SetPalette(SCR_1_PLANE, 0, RGB(0,0,15), RGB(0,0,15), RGB(15,15,15), RGB(15,0,0));
   SetPalette(SCR_2_PLANE, 0, 0, 0, 0, RGB(0,15,0));
   SetPalette(SPRITE_PLANE, 0, 0, RGB(15,0,0), RGB(0,0,15), RGB(0,15,0));
   PrintString(SCR_1_PLANE, 0, 2, 7, "Feels like");
   PrintString(SCR_2_PLANE, 0, 2, 9, "Starting over!");
   PrintString(SCR_1_PLANE, 0, 0, 0, "--------------");
   PrintString(SCR_2_PLANE, 0, 0, 0, "()()()()()()()");

   iSprite=0;
   iXpos=50;
   iYpos=50;

   SetSprite(iSprite, 88, 0, iXpos, iYpos, 0);

   while(1); // never fall out of main!!!
}

If we can compile and run this we’ll notice an X appearing towards the centre of the screen. Not very exciting, but that is our sprite. It’s not moving though, so lets fix that – change the while() loop as below:

   while(1)
   {
     iXpos++; 
     SetSpritePosition(iSprite, iXpos, iYpos);
     Sleep(1);
   }

Our sprite will now move slowly towards the right of the screen. Two things to note here… First, the Sleep() instruction just to slow it down enough to see what’s going on – it’s arguably better practice to actually tie your game loop into the VBlank either as an interrupt or by watching the timer, but a few judicious Sleep() commands is enough of a shortcut to get going. I won’t judge.

Secondly, note the function call now just uses SetSpritePosition() to move the sprite co-ordinates – all other parameters of the sprite will remain unaffected.

We can make the sprite follow a nice little sine wave if we change the code like so:

   while(1)
   {
     iXpos++; 
     SetSpritePosition(iSprite, iXpos, Sin(iXpos));
     Sleep(1);
   }

The last useful thing I have to say about sprites is the concept of chaining – basically, if we want to have sprites that are larger than 8×8 pixels we have two options. We could manually create a number of sprites and just move them in sequence ourselves like so:

   SetSprite(iSprite, 88, 0, iXpos, iYpos, 0); 
   SetSprite(iSprite+1, 88, 0, iXpos+8, iYpos, 0); 
   SetSprite(iSprite+2, 88, 0, iXpos, iYpos+8, 0); 
   SetSprite(iSprite+3, 88, 0, iXpos+8, iYpos+8, 0);

But then, each time we move them, we have to remember to move each sprite seperately and make sure that we’re doing it consistently – so that we don’t end up with a character’s feet sprouting out of their head or whatever. Who’s got the patience for that? So, instead, we can chain them. Chaining is just a flag which basically says – keep me with the previous sprite. Importantly, the x & y positions then become relative to the original unchained sprite. So, instead of the above we do this:

   SetSprite(iSprite, 88, 0, iXpos, iYpos, 0); 
   SetSprite(iSprite+1, 88, 1, 8, 0, 0); 
   SetSprite(iSprite+2, 88, 1, 0, 8, 0); 
   SetSprite(iSprite+3, 88, 1, 8, 8, 0);

Now, in order to move our group of chained sprites, we only have to move the first sprite in the series and the other 3 (or more) sprites will all move around relative to that position. This is a great way to create the illusion of large, brightly coloured sprites – although keep in mind the 64 sprite limit as it’s very easy to use them all up if you get too carried away.

Note that I am concentrating on a single sprite in order to make the example code easy to follow. In a real program, I would almost certainly create structures and arrays in order to indirectly access the various properties. I leave that as an exercise for the reader.

Coming next time. Time to take control…

 

 

A Splash of Colour

Now that we’ve got the basics out of the way, we can now start diving into something a bit more interesting. It helps at this point if you have basic understanding of the way that the NGPC graphics system works. The screen is divided into three distinct layers like so:

NGPCScreenPlanes

As you can see, the screen basically consists of two tile planes which form the display background, and a sprite layer that then sits on top of this.

Why do we need two tile planes? This is because NGPC tiles (or graphics bitmaps) can only display three colours. Well, four, but one of them will be transparent. By overlaying two planes on top of each other, we can create the illusion of a seven colour graphic.

We can see this in our STARTOVR project if we add a second plane to our Hello World splash screen like so:

void main()

{
   InitNGPC();
   SysSetSystemFont();

   // TODO: add game code - and remove hello world :-)

   ClearScreen(SCR_1_PLANE);
   ClearScreen(SCR_2_PLANE);
   SetBackgroundColour(RGB(0, 0, 15));

   SetPalette(SCR_1_PLANE, 0, 0, 0, 0, RGB(15,0,0));
   SetPalette(SCR_2_PLANE, 0, 0, 0, 0, RGB(0,15,0));
   PrintString(SCR_1_PLANE, 0, 2, 7, "Feels like");
   PrintString(SCR_2_PLANE, 0, 2, 9, "Starting over!");
   PrintString(SCR_1_PLANE, 0, 0, 0, "--------------");
   PrintString(SCR_2_PLANE, 0, 0, 0, "()()()()()()()");

   while(1); // never fall out of main!!!
}

If we compile and run that, we should see those lines of minuses and brackets look a bit like this:

startingoverv2

So, what are you seeing here? Essentially, exactly what we were talking about – the brackets are on Scroll Plane 1, and then the hyphens are on top of that on Scroll Plane 2. The net effect being to create a row of very lo-res TIE fighters.

Before we move on to talking about sprites, it’s worth pausing here and looking at this code in more detail – specifically to discuss palettes. A NGPC palette consists of four colours, typically a transparency/background base colour and three foreground colours. Each plane can support up to 16 individual palettes. Effectively, this means that you can have anything up to 96 colours (plus the background) displayed at any one time, albeit with only 7 colours within a single grid block.

In the example above, we are using two palettes – one per tile plane, both numbered zero.

SetPalette(SCR_1_PLANE, 0, 0, 0, 0, RGB(15,0,0));
SetPalette(SCR_2_PLANE, 0, 0, 0, 0, RGB(0,15,0));

So, when you define a palette, you specify the palette number or ID (I’ve been lazy here and just hard-coded palette 0, in the real world you would probably use a #define constant)  and then four colours. The first colour acts as a transparency against the overall screen background colour, and the other three are the palette foreground colours.

PrintString(), PrintDecimal() and other tile operations then simply define which palette to apply and the colours you choose here are then used. Only the fourth colour is used for PrintString() and PrintDecimal(). The other basic tile operation to keep in mind is PutTile() – this is mainly used to directly put a tile (see what they did there) into a scroll plane rather than indirectly as part of a string or number. This is more useful when we start talking about custom tile sets, but keep it in mind until then…

PutTile(SCR_1_PLANE, Palette, xPos, yPos, TileNumber);
SetBackgroundColour() sets the overall background colour – you’d probably normally use Black (0,0,0) or white (15,15,15) but I thought I’d set it to blue to show the effect. This basically acts as the default transparency colour for all your own graphics.

So, that’s the basics out of the way – you can do quite a lot just with text or block graphics, although the NGPC probably isn’t best suited for that rewrite of Zork you’ve always wanted to write…

In the next instalment, sprites!

Baby steps…

The story so far… I now have a compiler, emulator, tile editor and the NGPC Framework. If you want to play along then I have saved the versions of these that I am using here.

So, where to start…

There are a few bits of admin you need before you can start actually doing something useful.

First step – create a project folder. Simply unzip frmwrk3.zip into a new folder and rename to your preferred project name. By default this will build a NGP file called FRAMEWRK.ngp which probably isn’t what you want.

So start by editing the makefile and changing the NAME = line at the top like so:

NAME = STARTOVR

Use whichever name you like, by convention this should be eight characters, but it can be more or less if you like.

Secondly, edit carthdr.h and change the CartTitle to your project name like so:

const char CartTitle[12] = "STARTINGOVER";

There are some limits here that you need to be aware of. This must be exactly 12 characters long, no longer and no shorter. You can use spaces to pad this out if needed. It should also be as unique as you can manage – this will help if you ever try to bundle it on real hardware or on a multicart, but basically it’s just nice. Don’t tread on someone else’s toes.

Your last step is to create a batch file to do the make. You could do this manually each time using the command prompt, but generally it’s easier to just double click on a file and let the computer do all the hard work. For this, I create a batch file called “makengp.bat” which will look like this:

@path=%PATH%;C:\Data\Development\NGPC\t900\bin
@SET THOME=C:\Data\Development\NGPC\t900\
@PROMPT $P$_NGPC$G
@make
@cmd

Your path names should reflect the locations where you have installed the T900 compiler. This will run the MAKE for the project and leave you at a command line at the end – this is useful in case there are any compiler errors so that you don’t end up swearing at a blank screen wondering what went wrong.

Lets prove that it works, change main.c and edit the void main() function like so:

void main()
{
 InitNGPC();
 SysSetSystemFont();

 // TODO: add game code - and remove hello world :-)

 ClearScreen(SCR_1_PLANE);
 ClearScreen(SCR_2_PLANE);
 SetBackgroundColour(RGB(0, 0, 0));

 SetPalette(SCR_1_PLANE, 0, 0, 0, 0, RGB(15,15,15));
 PrintString(SCR_1_PLANE, 0, 2, 8, "Feels like");
 PrintString(SCR_1_PLANE, 0, 2, 9, "Starting over!");

 while(1); // never fall out of main!!!
}

Save this and run makengp.bat. You should have a basic NGP build now, which when run will produce the following output:

startingover

That’s it. I, and you if you are playing along, have now successfully compiled our first NGPC ROM. Granted, it doesn’t do very much yet, but we’ll come on to that next time…