Creating the Laser Blast
Step 1 - Create the Laser Class
Add a new class to your project called Laser.cs. Add the following using statements to the top of the class definition.
using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics;
As in our player and enemy classes, we will stub out the methods for Draw(), Update(), and Initialize(). We will also define a couple of new variables that represent the characteristics of our laser blast. Add the following definitions to the top of the Laser.cs class.
// animation the represents the laser animation. public Animation LaserAnimation; // the speed the laser travels float laserMoveSpeed = 30f; // position of the laser public Vector2 Position; // The damage the laser deals. int Damage = 10; // set the laser to active public bool Active; // Laser beams range. int Range; // the width of the laser image. public int Width { get { return LaserAnimation.FrameWidth; } } // the height of the laser image. public int Height { get { return LaserAnimation.FrameHeight; } }
Design Break:
As you look over the variables above, hopefully you are already getting cool ideas for power ups and enhancements. Perhaps the player can get bonuses to the laser's damage and speed characteristics. Will you permit your laser to fly all the way across the screen or will it fizzle out shortly after being fired? As a game designer these are all aspects you must consider. All of which will have a effect on game play and ultimately, the finished product. It's a good idea to write these ideas down as part of a game design before you begin coding. Having a formal game design will save you time during implementation. Now back to coding!
Add the following implementations for the Initialize(), Update(), and Draw() methods.
public void Initialize(Animation animation, Vector2 position) { LaserAnimation = animation; Position = position; Active = true; } public void Update(GameTime gameTime) { Position.X += laserMoveSpeed; LaserAnimation.Position = Position; LaserAnimation.Update(gameTime); } public void Draw(SpriteBatch spriteBatch) { LaserAnimation.Draw(spriteBatch); }
Step 2 - Add the Laser Texture Content and Load It
Locate the laser.xnb from the downloaded folder and add it to your project. In my project I placed this texture file in the \Content\Graphics folder. Once you have added this file. Right-click on the file in the solution explorer and click "properties". Set the "build action" setting to "content" and set the "copy to output directory" setting to "Copy if newer".
Next let's add the following variable near the top of the game class Game1.cs. This variable will hold the texture for our laser beam.
// texture to hold the laser. Texture2D laserTexture; // govern how fast our laser can fire. TimeSpan laserSpawnTime; TimeSpan previousLaserSpawnTime;I will mention the two TimeSpan variables in detail later. For now let's just add them just below the declaration of our texture variable. Add the following line of code the the LoadContent() method of the Game class Game1.cs.
// load th texture to serve as the laser laserTexture = Content.Load<Texture2D>("Graphics\\laser");
Step 3 - Initialize our Laser Object List
Design Break:
Before we can add our laser we must make a couple of game design decisions. Firstly, will the player be able to fire only one laser beam at a time or will we permit them to fire multiple beams in a hail of flaming hot destruction? Trust me, it matters! For this tutorial we will go with the latter option. We will establish a variable that governs a rate of fire for our laser cannon. That means we may have more than one active beam at a time. This requires us to create a collection of laser beam objects.
To store the volley of laser fire, add this list definition near the top of the Game1 class just below the laserTexture declaration:
List<Laser> laserBeams;Next add the following variable definitions to the Initialize() method. I will explain each one below.
// init our laser laserBeams = new List<Laser>(); const float SECONDS_IN_MINUTE = 60f; const float RATE_OF_FIRE = 200f ; laserSpawnTime = TimeSpan.FromSeconds(SECONDS_IN_MINUTE /RATE_OF_FIRE); previousLaserSpawnTime = TimeSpan.Zero;
The first variable should be fairly obvious. We are simply instantiating ("newing up") a strongly typed list of our Laser class. The next line is for nothing more than readability. I create a float to hold the number of seconds in one minute. Then I create another float to hold a rate of fire (lasers per minute). II use the seconds in one minute and the rate of fire variables to calculate a time span, in seconds, that governs how quickly my laser can fire another round. In this case I want a rate of fire of 200 rounds per second so my time span between shots will be less than one second (60/200). The very last line initializes a variable that will be set when a new laser is fired. When the time between "now" and the previousLaserSpawnTime is greater or = the laserSpawnTime then I can fire a new beam.
Step 4 - Add Code to Fire a Laser
To support firing the player's weapons I added the following two classes to the Game1.cs class.
protected void FireLaser(GameTime gameTime) { // govern the rate of fire for our lasers if (gameTime.TotalGameTime - previousLaserSpawnTime > laserSpawnTime) { previousLaserSpawnTime = gameTime.TotalGameTime; // Add the laer to our list. AddLaser(); } } protected void AddLaser() { Animation laserAnimation = new Animation(); // initlize the laser animation laserAnimation.Initialize(laserTexture, player.Position, 46, 16, 1, 30, Color.White, 1f, true); Laser laser = new Laser(); // Get the starting postion of the laser. var laserPostion = player.Position; // Adjust the position slightly to match the muzzle of the cannon. laserPostion.Y += 37; laserPostion.X += 70; // init the laser laser.Initialize(laserAnimation, laserPostion); laserBeams.Add(laser); /* todo: add code to create a laser. */ // laserSoundInstance.Play(); }
The FireLaser() method is pretty straight-forward. First, I check to see if enough time has passed between now and the last time I fired a laser. If it has then I record the current time and call the AddLaser() method.
The AddLaser() method simply initializes a new instance of the animation class using our laser beam texture. Then we set the laser's starting position to that of the player's current position. We assume the laser is emitted from the player's ship. Finally, we pass our animation class into the Initialize() method of our laser class and add it to our collection of Laser objects. Did you see the commented code to play the sound of a laser blast? That's a teaser for a future tutorial!
The last thing we need to do is to wire up our FireLaser() method to the press of the space bar on the keyboard or the X button on the XBox controller. Add this code to the UpdatePlayer() method of the Game1.cs class.
if (_currentKeyboardState.IsKeyDown(Keys.Space) || _currentGamePadState.Buttons.X == ButtonState.Pressed) { FireLaser(gameTime); }
Step 5 - Add Code to Track Laser Beams and Detect Collisions
Now that we can add laser beams to our collection we need to loop through all active lasers and update their positions and detect collisions with enemies. This part is pretty simple. Just add the following code to the Update() method of the Game1.cs class.
// update laserbeams for (var i = 0; i < laserBeams.Count;i++ ) { laserBeams[i].Update(gameTime); // Remove the beam when its deactivated or is at the end of the screen. if (!laserBeams[i].Active || laserBeams[i].Position.X > GraphicsDevice.Viewport.Width) { laserBeams.Remove(laserBeams[i]); } }
Notice that I never used the "range" variable I declared earlier in my code. I just decided that a beam would fly across the screen until it reached the right side or collided with an enemy mine.
Next we need to loop through all enemies and check to see if they are colliding with any of the laser beams in our collection. To do this, we need a nested loop. Add this code to the UpdateCollisions() method in the Game1.cs class.
Rectangle laserRectangle;
This rectangle is used to define the bounding box around a laser beam and is used in collision detection against the rectangles of enemies. Locate the section of code in the UpdateCollisions() method where we loop through our collection of enemies testing for collisions with the player. Add this code INSIDE the enemy loop as shown.
// detect collisions between the player and all enemies. enemies.ForEach(e => { //create a retangle for the enemy enemyRectangle = new Rectangle( (int)e.Position.X, (int)e.Position.Y, e.Width, e.Height); // now see if this enemy collide with any laser shots laserBeams.ForEach(lb => { // create a rectangle for this laserbeam laserRectangle = new Rectangle( (int)lb.Position.X, (int)lb.Position.Y, lb.Width, lb.Height); // test the bounds of the laer and enemy if (laserRectangle.Intersects(enemyRectangle)) { // play the sound of explosion. var explosion = explosionSound.CreateInstance(); explosion.Play(); // Show the explosion where the enemy was... AddExplosion(e.Position); // kill off the enemy e.Health = 0; //record the kill myGame.Stage.EnemiesKilled++; // kill off the laserbeam lb.Active = false; // record your score myGame.Score += e.Value; } }); });
Step 6 - Draw the Laser Beams
The last step is to add code in the Draw() method of the Game1.cs class to loop through each object in the laser beam collection and invoke it's draw method. Add this code:
// Draw the lasers. foreach (var l in laserBeams) { l.Draw(spriteBatch); }
Well That is it! If you have done everything correctly then your player's ship will now be armed with a deadly laser cannon. Experiment with the rate of fire and laser speed variables. Find a combination that is both fun and challenging.
Now you can blast away at enemies! |
Next time we will make these pesky enemy mines EXPLODE!
You can find the source code for this step here:
You can find the source code for this step here: