Part One - Design
Note: This tutorial series has been updated to compile under XNA 4.0. In reality, the only thing that needed to be changed for 4.0 is the removal of the parameter from SpriteBatch.Begin() as alpha blending is now the default and the parameter order for the call has changed in XNA 4.0. In addition to the 4.0 updates, I have corrected a couple of bugs as well.
Welcome to the first installment of the XNAResources.com Star Defense game tutorial! Through this series of articles, we will build, from the ground up, a simple, fully functional arcade game.
This first segement doesn't contain actual code. In all but the simplest software projects, there is a lot of work to do before the actual coding begins. While Star Defense isn't exactly a complex game, we still need to decide a few things before we leap into Visual Studio.
Overall Game Play Theme
For our purposes in this tutorial series, our basic game design is fairly straightforward. Star Defense is inspired by the old arcade games Defender and Stargate. Basically these games allowed the player to control a space fighter in a star field that was essentially mapped onto the inside of a cylinder, meaning that the player could fly endlessly either left or right and the "map" would loop back on itself. The top and bottom of the screen were the vertical movement limits.
For the purposes of this tutorial series, I have made the following design choices:
- The "game world" will be a 1920 pixel wide background image which will wrap around when the player reaches the edge. The display "portal" onto this world will be the screen in 1280x720 resolution, so the game world background should be 1920x720 pixels in size.
- We will also support a "parallax" layer of stars that scroll at a different rate above the background layer. This image will be 1620x720 pixels, and just consists of a few stars sprinkled over a mostly-transparent image.
- Our player's star fighter will move freely vertically, but moving left or right will scroll the map (as opposed to moving the star fighter), so the player's ship will always remain centered horizontally on the screen.
- Actual game play will consist of waves of enemies. Each wave will add an additional enemy, up to a maximum of 30 enemies on the map at a time. Our enemies will use a very simple (random) "AI".
- We will support randomly spawning powerups at set time intervals. Each powerup will be identified by a differently colored, animated sprite. The powerups will be:
- Extra Life
- Extra Super Bomb
- Faster Weapon Shots
- Dual Cannons
- Better Ship Handling
Obviously, in order to support the powerups above we will have:
- Super Bombs that destroy all visible enemies on the screen.
- Ship handling characteristics that determine how fast we can change directions
- Our game will be playable with either the keyboard or an Xbox 360 GamePad
- We will have a "title screen" and a "game screen", and our game can be in one of the two modes at a time.
Of course, all of these decisions are specific to the game that this tutorial will produce. You are free to change anything you like during the course of the series, naturally.
Here is a
quick sketch screenshot of what our game will look like in the end (the sketch I had was way, way too silly to put up on the internet):
Let me start by saying that many OOP (Object Oriented Programming) purists will definitely cringe at what they are about to see . When I originally started putting this game together I did the whole thing as one program, all in the game1.cs file.
In reconstituting the game for this tutorial series, I have gone back and refactored much of the code into more manageable classes. Even this refactoring, though, isn't a strict OOP approach, because there were some things I felt would be either more efficient to handle inline, or more easily explainable to illustrate the concepts I'm going for.
There are also a few choices I made based on speed concerns and garbage collection issues. As an example, let me discuss the way I handle enemies (and bullets and explosions for that matter). At first I considered using the "List" class to handle these. It seems simple enough to create a list:
List<Enemy> listEnemies = new List<Enemy>;
And, whenever I need to add a new enemy, just insert a new object into the list. When an enemy is destroyed, I just remove them from the list. Unfortunately, while this has some definite coding advantages, the approach has a couple of problems for me:
- That is a WHOLE LOT of object creation and removal. As you progress in the game, we have a max of 30 enemies in each wave. Add to that similar lists for each bullet the player fires and any explosions that take place as a result, and we are talking about generating a lot of object traffic. (Note: As it turns out, this isn't really that big a deal... In my work with XNA since I wrote this, I have often used lists like this creating entries for fired bullets, etc, without noticing a significant performance hit)
- You can't remove more than one item from a list in a foreach loop. I actually didn't know this until I tried this approach. I had the listEnemies implemented as above, and while updating my routine to check if a bullet impacts an enemy (and then destroy the enemy) I got a runtime error that the list had been changed and the enumeration could not continue.
So, when we get to implementing them, you will see that our Enemies, Explosions, and Bullets are all stored in arrays as persistent objects. They have fields that determine if they are active or not. Non-active entities are simply ignored during the Update and Draw routines.
As far as classes, we will do a bit of encapsulation here, and create classes for the following:
- AnimatedSprite.cs - This is a "generic" class that supports having a texture which contains a number of animations. The class will support frame rates for those animations as well as automatically looping them, etc. We will actually use the same class for Non-Animated sprites, which will simply be AnimatedSprites with a single frame of animation.
- Background.cs - This class will handle our scrolling background. It will also (optionally) have a "parallax" layer associated with the background that scrolls at a different rate than the full background.
- Player.cs - Contains the information about the player's star fighter, it's position on the screen, it's current display state, and it's "upgrade status" based on powerups that have been collected.
- Bullet.cs - The player's star fighter has cannons that can fire bullets... This class will handle those bullets
- Enemy.cs - Handles what we need to know about enemies. Each enemy has an AnimatedSprite associated with it, as well as positional and movement information. The class can also provide information about the position of the enemy for collision purposes. Finally we have a simple AI routine to direct our enemy's movements.
- Explosion.cs - Whenever an enemy (or the player) is destroyed, an Explosion object will be activated. This explosion has an AnimatedSprite associated with it which consists of a 16-frame explosion animation. Explosions also have positional information (of course) and will have movement information as well, since we will transfer a portion of the enemy's momentum to the explosion to create a drift effect.
Taking our game design into account, it is plain that we are going to need quite a number of art assets for our game. Personally, I can't do graphics. At all. I can't draw a sick figure that isn't crooked, so I farm all of this stuff out to Jason.
That brings up another point about assets. If you are just learning, it probably isn't a big deal to grab graphics off the net from anywhere you can find them to play around with, but we will, in most cases, be using original assets to avoid copyright and licensing issues. If you are planning to release your game, you will want to do the same thing.
The exception, of course, is if you can locate assets that are public domain and royalty free. This is the approach we took with our sound effects, since we don't have enough to warrant trying to go out and record our own.
Based on our requirements, we are going to need:
- A Title Screen (1280x720)
- A "Game Board" background image (1920x720)
- A "Parallax" background image (1680x720)
- A Game Interface Overlay (1280x720)
- A multi-frame Star Fighter (72x16, facing left and right, with and without engine thrust)
- An animated enemy ship image (32x32), XX frames
- A Power Up animation (736x32 = 23 frames of 32x32 spinning Power Up barrel)
- A bullet/laser thing
- A few animated explosions. I used a program called the Explosion Generator (http://www.positech.co.uk/content/explosion/explosiongenerator.html) to generate 8 of these, then repositioned them in to sprite strips so my final animation file is 1024x512 (8 different 64x64 explosion sequences of 16 frames each)
Finally, we are going to need a few sounds:
- The player's weapon firing
- An enemy blowing up
- The player blowing up
- Picking up a Power Up
That should give us a good starting point for our work, and some idea what to expect as we work our way through the series. We'll get into more details as we begin implementing the various portions of our code.
(Continued in Part 2...)