You can’t have an arcade with Donkey Kong can you – I couldn’t quite match the cabinet colours on this one, but threw an extra brick width in to show a slightly different way of building a square box with a screen…
Not my favourite of the builds so far, to be honest, but it gets the point across and I do like the bigger marquee size.
A simple one to follow from the Defender cab – this one uses yellow flat plates which aren’t too common (about 19p on the pick-a-brick site, albeit with fairly hefty postage), but again you could print your own stickers for the colour sides.
Again, side art images attached below – crop these as before – 15mm x 30mm for the side art, 15mm x 15mm for the screen and front panel (this might look better slightly cropped) and 15mm x 7mm for the marquee
About a million years ago I was involved with the online Videogame mag Way of the Rodent – technically, we’re still active, but the chances of a new issue are vanishingly close to zero, but for a while there we were, if not surfing the zeitgeist, at least paddling hard towards the waves. One of our biggest successes, back before things went viral, was something we Called Paper Arcade. A bunch of print-out-and-fold “papercraft” arcade cabinets, at Barbie scale. They were fun, and they were popular (and we made precisely £zero out of it because we were a bunch of idealistic idiots who thought that fun should be free – we still do)
Anyway, lockdown happened, we all know the story. But here I was stuck at home for six months (and luckily working the whole time), so spent a fair amount of time sorting through old boxes of stuff – trying to sift out the gold from the dirt.
One thing I found was an old box of Lego Dimensions game packs. Dimensions, as I’m sure you know, was a short-lived but actually quite fun videogame/Amiibo/Lego crossover project where you built little Lego models and then used them on the ingame portal to open different characters, levels and so on. One of the packs I had was the Midway Arcade – basically, Lego versions of Spy Hunter, Defender and so on. It was perfectly fine, but it had one problem.
Green? Since when were Defender cabs green? And what’s going on with that control panel? This is an abomination unto the Jarvis and frankly there’s no excuse for it.
So, I dug out the few odd bits of Lego I had lying around and, in idle moments, started fiddling.
And hence, a new lockdown obession was born, you can see them in the background… If you have one of these Defender sets and a few bits of Lego to hand, here are the build instructions – although I’ve changed a few details in this version – use the closest parts you have!
But what if you don’t have the Defender specific pieces to hand? Well, you can try ebay, but you can get inkjet printable white vinyl – it’s relatively expensive at something like a pound a sheet (so print more than one thing at once!), but it works brilliantly. I’ve provided some sample artwork below, but feel free to use your own – you will need to scale this artwork to 15mm x 30mm for the 2×4 plates, 15mm x 15mm for the 2×2 plate and 15mm x 7mm for the 1×2 plate. I find that Word is the easiest way to do this (right click and choose Format Size and Position), but you can use whichever software you are more comfortable with
Enjoy. More to come, including Pacman, Donkey Kong, Robotron, Battlezone and a Star Wars cockpit.
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:
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);
// Copy the tiles into the screen RAM
PutTile(SCR_1_PLANE, 0, 1 + iLoopX, 1 + iLoopY, bgTileBase+iTile);
// Draw the lines
// Then copy the bitmap back into tile memory...
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.
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.
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:
Offset the point by the origin
Transform the x-coordinate as point.x * Cosine(angle) – point.y * Sine(angle)
Transform the y-coordinate as point.x * Sine(angle) + point.y * Cosine(angle)
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)
u8 iPoint = 0;
cSin = Sin(VectorObject.RotationAngle);
cCos = Cos(VectorObject.RotationAngle);
iStartX = VectorObject.VectorList.x;
iStartY = VectorObject.VectorList.y;
// 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
iStartX = VectorObject.VectorList[iPoint].x;
iStartY = VectorObject.VectorList[iPoint].y;
We can now call that directly instead of our drawing code:
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…