Welcome to Ahchay.com

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:

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 8x8 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...