PlanetX Part 1
This is a series of tutorials in which we will create a game that looks something like this:
This is Part 1.
In this part, we will create the basic structure of our game. The end result will not be very fancy – only the background will be displayed. But we will be laying the foundation of our entire game. The source code and content for this part can be downloaded here.
Start by creating a new project – a XNA Windows Game. Let’s call it PlanetX.
The next step is to add the required variables and a few constants.
#region Variables GraphicsDeviceManager graphics; SpriteBatch spriteBatch; //Content Texture2D tx2Back; Texture2D tx2Player; Texture2D tx2Turret; Texture2D tx2Cursor; SpriteFont Font; //Game Classes Player Player1; //Input ButtonState PreviousFireKey; #endregion #region Constants float PlanetRadius = 260; float TurretElevation = 4; //Elevation of the turret over the player's origin float InitialBulletVelocity = 600; int MaxBullets = 1000; Vector2 ScreenCenter; #endregion
The Texture2D class is used by XNA to store 2D textures. The background, tank, turret and cursor textures are declared here. The SpriteFont class is used to store fonts which will be displayed in-game. We use this font to display important runtime values such as FPS (Frames per Second).
We will create the Player class a little later. It will store information about the tank.
An input variable “PreviousFireKey” is declared to store the previous mouse condition. More about this later.
The constants are used in the physics calculations. Tweaking their values will change the behavior of the bullets and the tank. The Vector2 ScreenCenter is used to store the screen center coordinates, which must also be the coordinates of the center of the planet.
Add a Frame Counter. I’ll post a tutorial on this later. Until then, look in the provided source code.
Create a new region to store Miscellaneous Functions. This will contain some handy functions used in the game.
#region Miscellaneous Functions private bool InitGraphicsMode(int iWidth, int iHeight, bool bFullScreen) { if (bFullScreen == false) { if ((iWidth <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width) && (iHeight <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height)) { graphics.PreferredBackBufferWidth = iWidth; graphics.PreferredBackBufferHeight = iHeight; graphics.IsFullScreen = bFullScreen; graphics.ApplyChanges(); return true; } } else { foreach (DisplayMode dm in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes) { if ((dm.Width == iWidth) && (dm.Height == iHeight)) { graphics.PreferredBackBufferWidth = iWidth; graphics.PreferredBackBufferHeight = iHeight; graphics.IsFullScreen = bFullScreen; graphics.ApplyChanges(); return true; } } } return false; } #endregion
I found this method here. I have been using it in every game since then. It attempts to resize the game window and recognizes whether the given hardware supports it.
In the Initialize method, write this:
protected override void Initialize() { InitGraphicsMode(800, 600, false); //Screen Size ScreenCenter = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2, graphics.GraphicsDevice.Viewport.Height / 2); Player1 = new Player(); base.Initialize(); }
CAUTION: I have given a generic 800×600 resolution in the source code. The game looks better on larger resolutions. Use the resolution that you monitor supports. My monitor has a resolution of 1280×720. I have provided the 800×600 background as well as a 1280×720 one. Use a background image which has the planet center at the screen center. For example, if you have a screen resolution of 1024×768, the planet center should be located at (512, 384) in the background image. If you do not do this, your tank movement will look weird.
The LoadContent method will look like this:
protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); //Load Textures tx2Back = Content.Load<Texture2D>("Graphics/PlanetX"); tx2Player = Content.Load<Texture2D>("Graphics/Player"); tx2Turret = Content.Load<Texture2D>("Graphics/Turret"); tx2Cursor = Content.Load<Texture2D>("Graphics/Cursor"); //Load font Font = Content.Load<SpriteFont>("Font"); }
We load all the textures and the font in this method.
We won’t change the Update method right now.
The Draw method will be as follows:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); //Draw Background spriteBatch.Draw(tx2Back, new Vector2(0, 0), Color.White); //Draw Explosions //Draw Bullets //Draw Tank //Draw Turret //Draw Cursor spriteBatch.Draw(tx2Cursor, new Vector2(Mouse.GetState().X, Mouse.GetState().Y), Color.White); //Draw HUD spriteBatch.End(); base.Draw(gameTime); }
We will draw just the background and cursor at this stage.
Now, let’s create the Player class. It will hold all the information about the tank.
The Player class will be as follows:
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace PlanetX { class Player { #region Member Variables private float m_Rotation=0.0f; private Vector2 m_Position; private float m_TurretRotation = 0.0f; private float m_AbsoluteTurretRotation; #endregion #region Properties public float Rotation { get { return m_Rotation; } set { m_Rotation = value; } } public Vector2 Position { get { return m_Position; } set { m_Position = value; } } public float TurretRotation { get { return m_TurretRotation; } set { m_TurretRotation = value; } } public float AbsoluteTurretRotation { get { return m_AbsoluteTurretRotation; } set { m_AbsoluteTurretRotation = value; } } #endregion } }
This class contains variables about the tank, which have been exposed as properties using get{} and set{} blocks.
Running the game now will display the background and the cursor. This may not seem much, but we have laid a strong foundation for further development of the game. Things will definitely get a lot more interesting in the second part of the series!

