You could easily argue game development is the hardest kind of programming to succeed at, simply because the results are so subjective – if gamers don’t like your game, that’s pretty much the end of it.
But it is also a heap of fun and a fast way to learn various aspects of coding. In the last few articles, we’ve looked at concepts as diverse as object-oriented programming (OOP) and collision detection.
Yet combine the two and it actually makes game development – on a very simple level at least – much easier to do.
Get the code!
Download the code for this project from here.
Unzip the zip file and you’ll find a second zip file – don’t unzip this second one.
Grab the NetBeans IDE + Java JDK bundle from Oracle. Once installed, open NetBeans, select ‘File > Import Project > From ZIP’, choose the second zip file and all of the project components should install.
Run the source code and the game should appear on your screen.
Game design before coding
Sure, you should keep an ‘agile’ mindset and allow room for brilliant ideas to pop up. But really, you have to sit down and scope out your game play first.
You could call it ‘systems analysis’, but here, we’ll just call it ‘what on earth are we doing in this game?’
In creating our modded game of ‘JPong’ in the previous guide, we learned how to do basic collision detection – checking if one virtual object has collided into another – but also how easily we could replace a black background with a cloudscape and the JPong balls with numerous World War II-era Spitfire aircraft.
Following on from that theme, our abridged gameplay analysis for this article is that we’re going to build a very simple WWII fighter arcade game that’s part ‘1942’ and part ‘Space Invaders’.
The source code is about 300 lines of code (tiny as games go) and the whole thing about 230KB compiled. It might be simple, but it still has many of the basics you’ll find in much larger games.
Using the right and left arrow keyboard keys, the fighter will sweep side-to-side at the base of the game window and fire ammunition with the ‘Ctrl’ key.
To give it some passing resemblance to real life, you’ll be able to fire at will (not just one bullet on the screen at a time as with ‘Space Invaders’) but you’ll also have a limited amount of ammunition.
So the basic gameplay is essentially this – shoot down all of the enemy fighters before you run out of ‘ammo’. If you don’t, you lose a ‘life’. Three lives gone and it’s ‘game over’.
Enemy flyers will be piloting the equally-new Messerschmitt Me888 but to keep our code size manageable for the moment, they don’t shoot back – their job is to just avoid your fire and run the player out of ammo.
There’ll be 20 enemy fighters to face, however, being only made out of cardboard, these planes need only one shot in the centre-fifth of the aircraft and it’s flame-outs and ‘nneeeyyyaaarrr-plonk!’
For starters, we have to monitor the movement of up to 20 (or possibly more!) enemy aircraft, plus our player fighter.
We have to keep track of ammo levels and, more importantly, monitor and track every bullet to see if it hits an enemy aircraft.
In terms of code, that’s more than enough to start with!
What we’ve just done is a very rudimentary analysis of how our game will work, the limits of its features ( ‘scope’) and roughly how it will play.
When you’re implementing OOP principles, one of the early steps is to look at your analysis and work out what are the objects you want to keep track of.
So far, we’ve got our fighter, up to 20 enemy aircraft and our fighter’s ammunition. This last one might seem weird, but bullets are objects, too – each bullet will have its own path, but as we said before, we need to monitor the movement of each bullet to know whether or not it’s hit something.
That means for the moment, we need three classes – ‘Fighter’, ‘Bandit’ and ‘FighterBullet’. Classes are normally represented visually using what’s called a UML (Unified Modelling Language) diagram – we’ve created one for the Fighter class to give you an idea.
Basically, it’s attributes first, followed by the methods of the class. Remember, a class is a template from which, we can make any number of copies or ‘instances’ – that should give you a hint about how we create multiple enemy fighters and the Spitfire ammo.
Class attributes, methods
Our Fighter will only have one instance (the single player), but it still has important parameters – for starters, it’s position.
If it’s moving across the bottom of the screen ‘a la Space Invaders, we need to know it’s X- and Y-axis coordinates, even though the Y-coordinate is fixed. We need to know its velocity (the speed at which it moves), its ammunition capacity, the number of lives remaining.
The enemy fighters or ‘bandits’ constitute a separate class because they have additional parameters (technically, we could have made the home fighter and enemy fighters all from a base class called ‘Aeroplane’, but we haven’t quite got to covering the topic of ‘interfaces’ just yet).
Unlike our fighter, bandits can move in both the X- and Y-axes, so we need their position, but we also need to give them an initial movement vector, which means we need to know the rate of movement in each axis of each plane (we’ll call these ‘dx’ and ‘dy’).
Remember, we want the enemy fighters to move independently around the screen. In practice, we’re going to do this the same way we bounced the JPong balls last article – we’re aiming for simple here, just to get the concepts across, but there’s no reason you couldn’t crank things up yourself!
Now for the FighterBullets. Each bullet fired by the fighter has to be monitored – not just for collision detection with an enemy aircraft, but also when it goes beyond the play screen or ‘map’.
So again, our bullet class needs position and movement attributes. You can see this in the source code.
Our classes also need methods that control what the class instances do – for example, our fighter, the enemy fighters and the fired bullets all need to be moved.
The bullets need to be tracked and we need to know if an enemy fighter has been shot down. These are all handled with in-class methods.
Frame, panel and map
But for our classes to be worth anything, we need a frame and a panel for them to be displayed on.
The basic GameDev2 class creates a resizable JFrame that’s initially 1024×768-pixels and on that JFrame, we create a JPanel instance called ‘Map’. It’s on this map object that we’ll draw our game.
You might remember in our last guide, we talked about how fast you need game frames to be drawn in order to see smooth movement.
Depending on the game, you can go as low as 30 frames per second and still get a reasonable result, but we’re going for better than ‘reasonable’, so we’ll set the rate for a nominal 50fps.
But what does that actually mean in practice? If you think of video, a 30fps playback rate means frames are displayed at 30 per second, or once every 33.33milliseconds.
For our game to run at 50fps, we need to update the movement of bullets, enemy fighters and our hero once every 20 milliseconds (1/50th of a second).
So essentially, we need to divvy up the processes into 20millisecond segments – and for that, we’ll bring in the Swing Timer class (Java has two timer classes – we’re using the Swing GUI timer because it works better with GUI apps).
The Swing Timer class allows you to create a timed delay, after which, an ActionListener class is called to execute whatever code you want to run.
The thing with the Timer class is that it keeps firing after each delay setting, so all we need to do is set the delay to 20milliseconds and we get our ActionListener code call firing off as required.
The key now is to ensure we do everything we need to do – move the fighter based on the user keyboard controls, move all of the enemy fighters and any bullets in play, check the bullets’ movement and do collision checks, check that all fighters remain within the Map panel/frame and adjust the movement as necessary – and do it all within 20milliseconds.
If it takes longer, the frame rate will either slow or movement will be jittery as the code struggles to keep the pace.
But really, we have just 20 enemy fighters to play with and even on my old 3GHz Intel ‘Sandy Bridge’ Core i5-2300 PC, I can crank up the number of enemy fighters to 5000 and it still works just fine.
When an enemy fighter has been hit correctly by a bullet (middle 20% of the fighter ‘frame’), we have to do something to make it look like it’s been hit, so the simplest way we came up with is to have a flame ball flickering behind the cockpit.
Each ‘instance’ of Bandit class has an ‘explodeCount’ attribute with the value of 50.
When an enemy fighter is hit, the ‘shotdown’ flag is set and each 20millisecond frame, we display a fireball PNG image just behind the central fuselage of the aircraft.
To make it flicker, we add in the Math.random() code to vary the size of the PNG as it’s displayed. Do this every 20milliseconds and you get a flameout-like flicker.
The ‘explosionCount’ integer is decremented every timer delay period, which gives a total of one second (or thereabouts, given the Swing GUI Timer isn’t perfectly accurate).
It implements the fighter.move() method to update the player’s positioning of the fighter and also uses a new coding toy called ‘Iterator’. An iterator is an object for traveling through an ArrayList of objects.
Right at the top of our code, we create an ArrayList of ‘bandits’ (enemy fighters) – here, we use the Iterator object as a means of incrementing our way through that ArrayList: while ever we haven’t reached the end of the list (that is, iterator ‘iBandit’ has a ‘next’ object in the array), we perform the bandit.move() method on each one.
We do the same thing for each bullet – we start with an ArrayList of FighterBullets and use an iterator to move through the list to update the position of each one and note its location. It’s also at this point that we check to see if it’s hit anything.
We also check to see if the position of the bullet has gone off the map (meaning it’s hit nothing). If so, we remove it from the ArrayList – this way, we only have to concern ourselves with the bullets ‘in play’.
Play with it!
As simple as this code is, it’s impossible for us to cover everything that’s going on – hopefully, if you’ve been following this series, you’ll be picking up things in the code we’ve covered before and seeing how we’ve used them here.
Either way, get stuck in and muck around with it – change the code, change parameters, swap lines, even delete lines, see what happens. Don’t be frightened to make the code crash – learn why it crashed.
We’re certainly not claiming our game project is the be-all of quality code, but coding is very much like learning the piano or guitar – no-one ever learned to play a music instrument by just looking at it.