Vectors. Vectors Everywhere.

Defenderoids, nothing more than a name really. But lets see where that goes… So, last time, we left our little bitmap engine creating a glorified star field, to not especially great effect.

Time to add some pizazz.

Vectors are great, but they are very mathematically intense, especially on a system without functional floating points like the poor old NGPC.

To start with then, we need to think about what constitutes a vector, and how to model that in code in such a way that we can work on it in integer maths.

A vector is, to all intents and purposes, a line. It has an origin, a direction and a length. It could also be represented as a start and end point if we prefer.

But a line isn’t very interesting, and probably not what you or I think about when we imagine vectors. I want shapes. Triangles, Squares, Asteroids, SPACESHIPS. For that, we need a list of Vectors, and a way to join them up.

So, what does that mean in practise? If we think of that as a series of points and each line is a vector from the last point to the next, then we can envisage how we might draw the five lines in sequence from that list like so:

XY
030
2020
300
4010
100
030

So, five vectors, needs six points – as I said, in this case it’s easier to think of the vectors as having fixed start and end points rather than trying to work backwards from a direction and length). Each vector hops from one point to the next in sequence – vector 1 from (0,30) to (20,20), vector 2 from (20,20) to (30,0) right the way through to vector 5 which joins the shape up by going from (10,0) back to (0,30). (remember that our bitmap origin in the NGPC is the Top Left corner, so all points are relative to that. There’s no particular need to join it up I suppose, but it wouldn’t be a very good asteroid if it wasn’t closed now would it?

Luckily, as well as the humble SetPixel() our NGPC C Library contains a handy function to draw a line on a bitmap – DrawLine(). So, enough theory for now – lets see how that works if we inject that into our bitmap code for the above example.

// Create the bitmap
CreateBitmap((u16*)bmpLogo, 144, 112);
CopyBitmap((u16*)bmpLogo, bgTileBase);

// Copy the tiles into the screen RAM
iTile=0;
for (iLoopY=0;iLoopY<14;iLoopY++)
{
	for (iLoopX=0;iLoopX<18;iLoopX++)
	{
		PutTile(SCR_1_PLANE, 0, 1 + iLoopX, 1 + iLoopY, bgTileBase+iTile);
		iTile++;
	}
}

// Draw the lines
DrawLine((u16*)bmpLogo,0,30,20,20,1);
DrawLine((u16*)bmpLogo,20,20,30,40,1);
DrawLine((u16*)bmpLogo,30,40,40,10,1);
DrawLine((u16*)bmpLogo,40,10,10,0,1);
DrawLine((u16*)bmpLogo,10,0,0,30,1);

// Then copy the bitmap back into tile memory...
CopyBitmap((u16*)bmpLogo, bgTileBase);
Voila, our first “vector” object

So far so good, but not very flexible. We need to step back a bit from the DrawLine() functions and define a couple of structures that can represent our shapes.

typedef struct Point
{
	s16 x;
	s16 y;
} POINT;

typedef struct ColourPoint
{
	s16 x;
	s16 y;
	u8 colour;
} COLOURPOINT;

typedef struct VectorObject
{
	POINT Origin;
	POINT Position;
	u8 Points;
	COLOURPOINT VectorList[128];
	u8 Scale;
	s8 RotationAngle;
} VECTOROBJECT;

First, we need a “point” structure – I use two slightly different ones both with and without a colour attribute. I could probably use the COLOURPOINT for both purposes and just ignore the Colour, but I prefer to keep things focused.

The main part of the VECTOROBJECT structure is the list of COLOURPOINTS – I’ve coded this to a maximum of 128 points because we can’t have open ended arrays within a structure. There are then a few additional attributes around this big list of points (as in our example basically) which will be used to define the position of the object within our bitmap, the scale, and the rotation angle – more on that in a minute. As we move on, we’ll extend this to include behavioural attributes for the object such as speed, direction and rotation. Lets look at our example again but this time using the above structure.

// Create the bitmap
CreateBitmap((u16*)bmpLogo, 144, 112);
CopyBitmap((u16*)bmpLogo, bgTileBase);

// Copy the tiles into the screen RAM
iTile=0;
for (iLoopY=0;iLoopY<14;iLoopY++)
{
	for (iLoopX=0;iLoopX<18;iLoopX++)
	{
		PutTile(SCR_1_PLANE, 0, 1 + iLoopX, 1 + iLoopY, bgTileBase+iTile);
		iTile++;
	}
}

myVectorObject.Points=5;
myVectorObject.VectorList[0].x = 0;
myVectorObject.VectorList[0].y = 30;
myVectorObject.VectorList[0].colour = 1;
myVectorObject.VectorList[1].x = 20;
myVectorObject.VectorList[1].y = 20;
myVectorObject.VectorList[1].colour = 1;
myVectorObject.VectorList[2].x = 30;
myVectorObject.VectorList[2].y = 40;
myVectorObject.VectorList[2].colour = 1;
myVectorObject.VectorList[3].x = 40;
myVectorObject.VectorList[3].y = 10;
myVectorObject.VectorList[3].colour = 1;
myVectorObject.VectorList[4].x = 10;
myVectorObject.VectorList[4].y = 0;
myVectorObject.VectorList[4].colour = 1;
myVectorObject.VectorList[5].x = 0;
myVectorObject.VectorList[5].y = 30;
myVectorObject.VectorList[5].colour = 1;

myStartPoint = myVectorObject.VectorList[0];
for (iLoop=1;iLoop<=myVectorObject.Points;iLoop++)
{
	DrawLine((u16*)bmpLogo,(u8)myStartPoint.x,myStartPoint.y,(u8)myVectorObject.VectorList[iLoop].x,(u8)myVectorObject.VectorList[iLoop].y,(u8)myVectorObject.VectorList[iLoop].colour);
	myStartPoint = myVectorObject.VectorList[iLoop];
}

// Then copy the bitmap back into tile memory...
CopyBitmap((u16*)bmpLogo, bgTileBase);

If we run that, then we should get the same shape again – just with more lines of code (and yes, I know that the constructor can be simplified, at the expense of readability). But, crucially, we’ve now abstracted the shape definition away from the drawing – and we can now further abstract that to do more stuff. Remember we had a couple of attributes in the VECTOROBJECT structure for rotation and scale. After all, if they were just going to stay the same size and face in one direction, a sprite would be much easier.

I won’t dwell on the maths too much – there are far better places to go for that if you are interested – I’d recommend Ian Bell’s page “Maths for programmers” – it’s just brilliant. And yes, it is that Ian Bell.

So, the two things we want to do most will be to scale the shape – I won’t dwell on that, as essentially all we have to do is “multiply” the .x and .y coordinates by our scaling factor. For speed reasons, I will always try and use the boolean left and right shift operators for multiplication and division where it makes sense, so multiplying by factors of two.

Rotation is a bit more complex, and needs three things:

  • a point of origin, that we are going to rotate our object around
  • a rotation angle
  • Sine and Cosine functions.

The basic method to rotate a point is simply:

  1. Offset the point by the origin
  2. Transform the x-coordinate as point.x * Cosine(angle) – point.y * Sine(angle)
  3. Transform the y-coordinate as point.x * Sine(angle) + point.y * Cosine(angle)
  4. Offset the rotated point back to it’s relative position from the origin

So, putting both of those together, and further abstracting our “drawing” routine into a function gives us:

void DrawVectorObject(u16 * BitmapAddress, VECTOROBJECT VectorObject)
{
	s16 iStartX;
	s16 iStartY;
	s16 iEndX;
	s16 iEndY;
	s16 iTempX;
	s16 iTempY;
	u8 iPoint = 0;
	s8 cSin;
	s8 cCos;
	
	cSin = Sin(VectorObject.RotationAngle);
	cCos = Cos(VectorObject.RotationAngle);

	iStartX = VectorObject.VectorList[0].x;
	iStartY = VectorObject.VectorList[0].y;

	while (iPoint++<VectorObject.Points)
	{

		// Modifier here is to find the centre of rotation
		iStartX = (iStartX*VectorObject.Scale)-VectorObject.Origin.x;
		iStartY = (iStartY*VectorObject.Scale)-VectorObject.Origin.y;

		// rotate point.
		iTempX = ((iStartX * cCos)>>7) - ((iStartY * cSin)>>7);
		iTempY = ((iStartX * cSin)>>7) + ((iStartY * cCos)>>7);

		// translate point back to it's original position:
		// Modify back from the centre of rotation above, and then add the X & Y co-ordinates
		iStartX = (VectorObject.Position.x>>7)+iTempX+VectorObject.Origin.x;
		iStartY = (VectorObject.Position.y>>7)+iTempY+VectorObject.Origin.y;

		iEndX = (VectorObject.VectorList[iPoint].x*VectorObject.Scale)-VectorObject.Origin.x;
		iEndY = (VectorObject.VectorList[iPoint].y*VectorObject.Scale)-VectorObject.Origin.y;

		// rotate point
		iTempX = ((iEndX * cCos)>>7) - ((iEndY * cSin)>>7);
		iTempY = ((iEndX * cSin)>>7) + ((iEndY * cCos)>>7);

		// translate point back:
		iEndX = (VectorObject.Position.x>>7)+iTempX+VectorObject.Origin.x;
			//if (iEndX<0) iEndX=0;
		iEndY = (VectorObject.Position.y>>7)+iTempY+VectorObject.Origin.y;

		// Bounds check to ensure that rotated points are still within the bitmap boundary
		if (iStartX>=0&&iStartY>=0&&iEndX>=0&&iEndY>=0&&iStartX<=BitmapAddress[0]&&iStartY<=BitmapAddress[1]&&iEndX<=BitmapAddress[0]&&iEndY<=BitmapAddress[1])
		{
			DrawLine((u16*)BitmapAddress,(u8)(iStartX),(u8)(iStartY),(u8)(iEndX),(u8)(iEndY),VectorObject.VectorList[iPoint].colour);
		}
		iStartX = VectorObject.VectorList[iPoint].x;
		iStartY = VectorObject.VectorList[iPoint].y;
	}
	
}

We can now call that directly instead of our drawing code:

myVectorObject.Position.x = 0;
myVectorObject.Position.y = 0;
myVectorObject.RotationAngle = 0;
myVectorObject.Scale = 1;

DrawVectorObject((u16*)bmpLogo,myVectorObject);

Which will give us the same shape again, or we can change the scale, position and angle to do something more interesting.

myVectorObject.Points=5;
myVectorObject.VectorList[0].x = 0;
myVectorObject.VectorList[0].y = 3;
myVectorObject.VectorList[0].colour = 1;
myVectorObject.VectorList[1].x = 2;
myVectorObject.VectorList[1].y = 2;
myVectorObject.VectorList[1].colour = 1;
myVectorObject.VectorList[2].x = 3;
myVectorObject.VectorList[2].y = 4;
myVectorObject.VectorList[2].colour = 1;
myVectorObject.VectorList[3].x = 4;
myVectorObject.VectorList[3].y = 1;
myVectorObject.VectorList[3].colour = 1;
myVectorObject.VectorList[4].x = 1;
myVectorObject.VectorList[4].y = 0;
myVectorObject.VectorList[4].colour = 1;
myVectorObject.VectorList[5].x = 0;
myVectorObject.VectorList[5].y = 3;
myVectorObject.VectorList[5].colour = 1;
myVectorObject.Position.x = 2048;
myVectorObject.Position.y = 2048;
myVectorObject.RotationAngle = 16;
myVectorObject.Scale = 6;

DrawVectorObject((u16*)bmpLogo,myVectorObject);
It’s moved! Finally.

There are a couple of things to note here. Firstly, I use a larger scale for the position variables, so that objects can move at different paces, but still move at the right relative speeds.

You’ll also notice that the point definitions of the base object have changed slightly – this is just to make the vector definition as small as possible so that we have more flexibility to scale it up. There is no support here for scaling the object down to make it smaller, but there’s no reason why we couldn’t do that too I suppose.

Secondly, sine() and cosine() as defined in the library are integer values – remember how I mentioned that we don’t have a floating point on the poor old NGPC? So, we need to shift these down by 128 AFTER the multiplication in order to pretend that we’re multiplying by a decimal point. Also, we use a 256 degree circle for the angles – primarily for speed reasons. Everything is better when it’s a power of two.

I’m going to leave this post here, as I think I’ve waffled on plenty well enough about the theory for now. Tune in next time when I might actually start doing something about writing a game…

Advertisements

Some things come from nothing

There’s something rather absurd about coding games on obsolete platforms. They’re limited in weird ways – number of colours, sprites, controls, speed, you name it, it comes with limitations.

Life would be much easier with a copy of Unity of whatever, I could bring my ideas to life in moments rather than the weeks it takes to get a small NGPC sketch to the point where it can legitimately be called a game (months, or, lets be frank, years is probably more accurate). Hell, I might even be able to bung it up on one of these new-fangled stores and make a few pennies.

But where would be the fun in that?

You see, one of the things I find most enjoyable about coding on the NGPC are the limitations. It’s as though the machine is sitting there saying “Come on then, I have two limited colour planes for backgrounds, 64 tiny sprites, a joystick with two and a half buttons, a squawky buzzer and a 6.144MHz CPU. Go on then, make that do something amazing. I dare you.”

You know what little machine. Challenge accepted.

So, what’s the ultimate course of action with this approach? You’ve guessed it, why not take that already limited palette and try and use it for something that it patently is not suited for?

Enter – Bitmap mode. This was something I did for the C Framework library more than ten years ago now, because I wanted nice swoopy backgrounds for my Juno First game. It grew out of the times when you had to build tiles manually in hex editors and after I rolled my own very basic tile editor, I realised I could build tiles in engine just as easily.

I’m not going to go into details about how it works (basically applying boolean logic directly into the tilespace to set/reset the individual bits of an 8 byte tile, I’ll leave it as a challenge for the reader to work that out). Most of my games have some form of bitmap support – from the bootup “rug” pattern in Joust and Defender or the star background in Juno First, but generally all the heavy lifting is done with Sprites and Tiles as SNK intended, so I thought it would be “fun” to try and write a game entirely in bitmap mode.

Now, cards on the table, I tried this several years ago by trying to write a version of Qix but I got myself thoroughly tied up in knots doing that and couldn’t face going back to the code again, so this time I’m starting from scratch.

Buckle up, this is going to be a long one…

So far, all I really have is a name “Defenderoids” – which I came up with simply because I couldn’t decide whether to do a Defender clone or an Asteroids one. I have little to no idea how this might play at the moment, it is “just” a name*.

Bitmaps on the NGPC are created within a tileset which then gets echoed to the screen as an array. The basic approach is as follows :

void Defenderoids()
{
	u16 bmpPlayField[252][8];
	CreateBitmap((u16*)bmpPlayField, 144, 112);
	CopyBitmap((u16*)bmpPlayField, bgTileBase);
	//Copy the bitmap to SCR_1_PLANE
	// Watch the order...
	for (iLoopY=0;iLoopY<14;iLoopY++)
	{
		for (iLoopX=0;iLoopX<18;iLoopX++)
		{
			PutTile(SCR_1_PLANE, 0, 2 + iLoopX, 1 + iLoopY, bgTileBase+iTile);
			iTile++;
		}
	}
}

That won’t look like much – since we’re not actually putting anything into the bitmap. But that’s essentially the blank canvas that we can then use.

We can then use SetPixel() to write individual pixels to the screen. We’ll start with a star field…

void Defenderoids()
{
	// Variable declarations
	u8 iTile;
	u8 iLoopX;
	u8 iLoopY;
	u8 iLoopStar;
	u16 bmpPlayField[252][8];

	// Create a "bitmap" array
	CreateBitmap((u16*)bmpPlayField, 144, 112);
	// Copy the bitmap array into the tilespace
	CopyBitmap((u16*)bmpPlayField, bgTileBase);
	//Copy the bitmap to SCR_1_PLANE
	iTile = 0;
	for (iLoopY=0;iLoopY<14;iLoopY++)
	{
		for (iLoopX=0;iLoopX<18;iLoopX++)
		{
			PutTile(SCR_1_PLANE, 0, 2 + iLoopX, 1 + iLoopY, bgTileBase+iTile);
			iTile++;
		}
	}

	// Draw a "random" star  field
	for (iLoopStar=0;iLoopStar<25;iLoopStar++)
	{
        	iLoopY = QRandom()&gt;&gt;1;
	        iLoopX = QRandom()&gt;&gt;1;
        	SetPixel((u16*)bmpLogo,(u8)(iLoopX),(u8)(iLoopY),QRandom()&gt;&gt;7);
	}
}

I’ll leave this post here, next time I’ll dig into how to create and use some simple vector objects.

* Although names are important…

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

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…