| Here now I will take you step by step through creating your own Galaga/Galaxian style space shooter game. When its finished it will feature the following:
Scrolling Starfield
Particles
Infinite Levels
Increasing Difficulty
It will hopefully look something like this:
|
 |
Here's the images you will need (please resave as .bmp):
|
| To save time I have left the sound and music portion out so we can focus on the code. This tutorial goes through all the code in order so everything may not make sense at once. For example you will see me calling functions before they have been declared yet. If necessary just skim around until everything seems to fall into place.
Setting up
I'm not going to go on about the theory behind creating a space shooter. We have all played tons of them millions of times. What I will try to do is go through the code slowly and explain everything to the best of my ability. Load up Blitz and grab your favorite beverage, because here we go!
|
|
Ok what we have done here is pretty basic. First we setup our Graphics mode to a 320 x 240 resolution with a color depth of 16 bits and set it to fullscreen. We then use the AppTitle command and pass it the string "Galaxiga" to give our program a name on the TitleBar. SetBuffer BackBuffer() tells Blitz we want to use double buffering. Please refer to the Blitz Docs for a deeper understanding on double buffering. SeedRnd(MilliSecs()) is like the old QBasic command RANDOMIZE TIMER. SeedRnd tells blitz to base all its random numbers off the MilliSec at which the program was executed (if we only use it once). Something worth noting at this point are the different screen modes we can use.
1 - FullScreen
2 - Windowed
3 - Resizable Window (Requires Hardware Acceleration)
Now that we have the bare essentials ..... lets load some images.
|
|
Just for conveniece we make all the Variables holding the images Global. This allows them to be visible to functions. I realize that making everything Global is not the best thing for speed but this game is so small and tidy I don't think anyone will notice ;). The LoadImage command simply assigns the Loaded Image to whatever var we give it. This allows us to say DrawImage Var later. LoadAnimImage is used when we have an image containing more then one frame. In this case its used to load our three different color Aliens. Here's its syntax
|
|
Our Alien image contains 3 16x16 frames so we just plug this information into the AnimImage command. Now we are going to declare all the variables that we will use throughout the game.
|
|
These Variables are explained in commenting. They are not really important until we start to use them. The reason AS has a # sign beside it is because we want to declare it as a Float and not an Integer. Floats allow for decimal points and let us use 1.25 as a value, or even 0.005. Floats should be used when your looking for accuracy. Lets get into types next ( Don't be scared ;) )
|
|
Here we have created a type for the player's bullet, the aliens, your ships engine particles, and the stars which will make up our scrolling starfield. The fields you see are the variables each type will hold. Just think of types as a container that we can tell to hold as many of anything that we want. Later we will assign functions to create and render the objects these types hold. Lastly before we jump into the 'Main' or our program we will set a readable font:
|
|
|
The LoadFont syntax goes (Font$, Height, Bold?, Italics?, Underlined?)
Main
Herein contains the bulk of our game. Lets get started with some cleaning up.
|
|
The Reset label and everything contained is pretty much irrelevant at the moment. What we are doing here is changing the aliens frame of animation to match what level we are on and then going through all our types and deleting each object within. We will goto this label when the player dies. This will basically erase everything onscreen and start us on a clean slate. You may have noticed the names in front of our types, such as evil.Enemy. Evil is the collection name we have given to the type Enemy. You will see all this assigned later on. Next we look at the Level label.
|
|
The Level section simply displays the players current level and has them press ENTER to continue. First we clear the screen with a CLS and then set our Text to display in white. We do this with the RGB values of 255, 255, 255. The Text command places the word "Level" in the center of the screen and then attaches our Level variable on the end by using + Level. This code will loop itself until we get ENTER from the user. Text knows to place the level number in the center because we use 320/2 - 20 and 240/2 for X and Y positions. This is roughly our screen resolution cut in half.
|
|
You may ask yourself why we are reassigning some variables here. We do it because this is where the game will go after each level is done. Here we need to re center our ship and create 30 new aliens. The For Next loop you see goes from 1 to our AlienNum value which is 30. It calls our CreateAlien() Function (which we will create shortly) and moves the Aliens X position over 20 pixels each time. This lines the aliens up from left to right. When we are at the 10th and 20th aliens we reset their X position to 10 and move them down 20. This creates 3 rows of 10 aliens.
|
|
This section of code is where everything gets rendered or drawn to the screen. We also put our Timer into effect here. The method i'm using is very inefficient but this tutorial is geared towards newbies and it provides all this game needs. First we create our While loop. Our while condition is Keydown(1). This tells blitz to loop everything in between While and Wend until we press Escape. We then create two labels. The label Main is where the programs delays for 1 MilliSec() then goes on to Render. We do this so that all machines that run this game will run the game at the same speed. Without this 1 millisecond wait the games framerate would depend solely on the user's monitor refresh rate. Every user's PC identifies this 1 millisecond delay the same. If your in the mood for a little foolery try messing with this delay to make the game run in slow motion :). If the 1 millisecond has passed then we move on to the Render label. First we reset the timer so that we can check it again. All functions are called next. Always remember this about drawing objects: Draw them in the order you want them to be displayed. I know this sounds rudimentary but we must be sure to draw things in the proper order. Here we draw Stars first, then the engine particles, then the aliens, then the bullets, and lastly we draw our ship on top of it all. CLS clears the screen and we set our Text color again. We then use the Text command to display the players current score and amount of lives. We use the DrawImage command and plug our image and X, Y variables in.
|
|
This next bit is quite a lot of code at once but its all really simple. Our 4 keydowns at the top are for moving our ship in 4 different directions. We then set boundaries for our ship so that he cannot move off the screen or go up to far and mingle with the aliens. To do this we just check if its X or Y position is greater or less then a certain value and if it is then we set it 1 under the limit. The next line of code does a few different things. First it checks to see if you have killed all the aliens. If AlienNum = 0 it speeds them up by .10, moves you to the next level, and goes to our Reset label where it begins all over again. The next line checks to see if we have been hit and subtracts 1 from our lives and gotos Rest if so. Our If Lives = -1 statement tells blitz to goto our GameOver label which will end the game. This final piece of code before we tie off the main loop is rather tricky. First it checks to see if we have pressed left control and then it checks to make sure your BulletTime requirements have been met before it CreatesBullet(1). BulletTime + 175 means that unless 175 millisecs have passed since we have last shot then don't allow us to. We reset our Bullet Timer with each CreateBullet(). We must use this delay or else our ship would be able to fill the screen with thousands of bullets! We pass CreateBullet(1) to tell the function the bullet came from us. If we use (2) then it will know the bullet is coming from the alien and adjust accordingly. Last Flip our buffer, Wend the loop, and End if we press Escape. Now for.... "gasp"
Functions
Functions are what will control the creation and rendering of all our objects. If you noticed above we called all our functions, and now we will create them. |
|
This function controls all our bullets in the game both player and enemy. It only creates them and does not display them or handle collision. First we start a new collection for the Type bullet and name it 's'. You see we have passed the Create Bullet function (Src). Src tells the function whether to have the bullet come from the player (1), or from the aliens (2). If the Source is 1 then we start the bullet at the players current position and reset the BulletTimer. If the Source = 2 then we do the same for the enemy. We have a s\Src so that the when we loop through the types we will know where the bullet came from there as well. Last we reset our 'are we shooting' flag because we just finished shooting.
|
|
These three functions handle the creation of our Aliens, Stars, and engine particles. The enemy type gets the collection name evil }:), Spark gets engine, and Stars get shiny. Enemies are created at their default location and their 'Are we shooting' value is set to 0. The D field will use two values: 1 if the alien is traveling right and 2 if its traveling left. All aliens will be moving to the right at first so we set this to 1. Next the CreateSpark function assigns all particles to spawn underneath the players ship and at a random location so they don't all come from the same point. engine\C gets a random number 1-3 so that we can color them either red, orange, or yellow. Finally we finish up our create functions with CreateStar() We pick a random X pos based on the screen width and start it at the top. Since we have two star bitmaps we need to assign T a random 1 or 2 so that we get both kinds of stars. Now lets move to the rendering.
|
|
From here on out the rendering functions get down and dirty with types. If you don't have a good understanding of types please refer to some of the other great tutorials/ articles on blitzcoder. We will go through this line by line because it is pretty hard to grasp at first.
We begin a for next loop that will go through every bullet we have created. If the s\Src = 1, which is the player, then we move the bullet up the screen by four pixels. If the s\Src = 2, the alien, then we move its bullet down the screen. We then draw the bullets. Depending on the source we draw a simple 1, 1 rect for the ship's bullets or our alien laser graphic for the enemy.
Another loop is started which goes through all the aliens on screen. We do this so that we can check collision between our bullets and the aliens. We check to see that the s\Src = 1 so that the aliens cannot shoot themselves then if we have a hit we begin a then endif. Depending on what color our alien is we give the player a score and delete the alien.
Last we subtract one from the aliens ranks and endif. As we checked for player to alien bullet collision we must now do vice versa. Remember we don't need to start another loop because the players ship is not a type. If s\Src = 2 and the aliens shot hits us then we set our Over flag to 1 and flush the keys. Setting over to 1 allows us to subtract a life when the program goes back to the main loop. That ends our collision checking.
Lastly we delete the bullets if they reach either extreme of the Y plane. We then finish our type loop and end the function. |
|
This function handles our enemies and how they move/shoot. We start another loop that goes through all our aliens. If their direction is 1 then we know we must move them right by their alien speed float (AS#). If its 0 then we move them left by the same amount.
The next two lines check the aliens position on the X plane. If the aliens reach the left side then we make them start moving right, and vice versa. This next bit of code creates two temporary random numbers 1-350. We compare the two and if they happen to be the same then we Create a bullet and set our evil\S flag to 1. This tells us the alien is shooting. If you would like to have the aliens shoot more often, then simply lessen the amount of random numbers it picks.
The next line renders the alien. We then make sure that if the aliens reach the bottom of the screen then we set our Over flag to 1 so that our player loses a life. Lastly we check to see if the Alien hits our player's ship and if it does then he loses a life. We close this function up by finishing the loop and ending the function. |
|
This chunk above is my favorite part of this program as it gives us a bunch of pretty engine particles to look at. Hopefully you've realized we must start another loop to go through all our particles. The particle then gets moved either left or right and down by 1 or 2 pixels randomly. We then check to see which color it was assigned randomly in our CreateSpark() function earlier and color it accordingly. Last we render it and make sure to delete it if it reaches the bottom of the screen.
|
|
Our final function is thankfully the simplest. All we do is move the stars down by 3 pixels and depending on its type draw the appropriate bitmap. As always we delete it if it reaches the bottom of the screen.
Finishing Touches
We are almost finished with the whole game! All thats left is to give our player the Game Over screen if he has lost. You may recall we checked to see if our player was out of lives in our main loop. If he was it went to the label GameOver, we will create it now.
|
|
| |