Introduction
I was
feeling boar and wanted to do something innovative. I love playing games and
always wondered
- How game
will be developed?
- How
characters moves etc?
For this
weekend I gave a shot to XNA Framework and For the App Innovation Contest, I
propose creating a Fighter Space Ship game. It’s my first attempt to game
programming,
As the name
suggests, you will be driving a space ship in galaxy and protecting yourself
from meteors. With this game, we also wanted to demostrate ultrabook capabilities.
Our game will demonstrate two main feature of ultrabook -
Touch Aware - The game will be touch aware, there will be two buttons, one which will speed up your space ship and another will put brake on space ship. This will give you greate control while driving space ship.
Accelerometer - The game will have accelerometer support. Player can just lift their ultrabook and feel the driving.
That way, the game need not to change when it ports on other devices like, windows phone, tablets etc.
Background
In order to
understand this, you should have basic knowledge of C# programming. Your
concepts with OOPs should be clear. As in game each and everything will be
demonstrated to you as object.
Let's Begin
We will be developing a 2D game here.
I have started learning XNA by creating some 2D games. For 2D games first you got to learn about game templete, how things execute, game life cycle, how to show images on screen, how to move things, collision detection etc. Once you grab these basics then creating 2D games is just your creativity.
I will start right from scratch so even if you are developing your first game this tutorial will help you.
1) Prerequisites
In order to start developing XNA game. First you should have XNA Game Studio installed on your machine. XNA Game Studio have different vesions and currently running version is 4.0. Even if you install visual studio 2008 you will get XNA game studio 3.0 installed on your machine by default and with visual studio 2010 you will get game studio 4.0 installed.
If you dont have XNA game studio installed on your machine just make a google search, download it and intstall on your machine.
Obviously we need Visual Studio.
2) Understanding Game Template
2.1) Open XNA Project
I will be quickly explaining this section else this article will become too lengthy.
Open Visual Studio -> Select new project -> Select XNA Game Studio-> Select Windows Game.
Name it as FirstGame. Here we have different kind of templates for windows phone games, Xbox and windows game etc
XNA is very easy framework for developing games, it will hide all internal details and complexity and we just need to imagine and develop game. Here we don't just drag drop things, all you got to do is by coding only.
2.2) Understand Basics
This will open the Game Project for us. Notice you will have two sub project, FirstGame and FirstGameContent
FirstGame project will contain all your game logic and FirstGameContent project will contains all your game contents. Game content can be your images, audios, fonts and animations etc.
Your FirstGame project will contains program.cs which is starting point for your game and game1.cs file in your project, which is almost like you game only. This is starting point of game which will invoke other objects on screen. Let's look at its methods.
before proceding further lets just think of a game, how it should be, how it should execute in an endless manner. Let's look at below pseudocode.
Game1() – General initialization (Game1.cs)
Initialize() – Game initialization (Game1.cs)
LoadContent() – Load Graphics resources (Game1.cs)
Run() - Start game loop (Program.cs). In every step:
Update() - Read user input, do calculations, and test for game ending (Game1.cs)
Draw() – Renderization code (Game1.cs)
UnloadContent() – Free graphics resources (Game1.cs)
As the aboe pseudocode explains us everything. From program.cs we will create game1 object and invoke it.
The Draw method of game1 will call initialize only one time, then it will load content and start drawing objects on screen. In one second, on Xbox or Windows the update method will be called 60 times, so this is the place where we will read inputs, update game objects etc. Finally based on user input we will stop game and then its unload content method will be called.
Now look at below snippets, which is exactly same.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
TargetElapsedTime = TimeSpan.FromTicks(333333);
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
as its structure automatically explaining every thing. Till here you should have basic understanding of game, how it works etc. So we will start building game now and simultaneously I will keep explaining objects creating, moving and other animation concepts.
Start Game Development
Before stating developing Fighter Space Ship game, we need to plan for game, what all features will be there, how game will proceed, game state management.
What this game will do, you will be having a space ship which will be controlled by user input. There be meteors in galaxy will be moving and trying to block you. We need to escape from them and reach to our destination.
From above statement, we can thing of certain items as compnents of game.
- Your space ship will be an object which will be controlled by user.
- Meteor will be an object.
- Your game1.cs, main object will be controlling everything. Galaxy need not be an object, as we can draw an galaxy image in game1.cs only.
Below code for space ship will be used as an component
class SpaceShip : DrawableGameComponent
{
Texture2D shipTexture;
Vector2 shipPosition;
const int ShipHeight = 84;
const int ShipWidth = 84;
public SpaceShip(Game game)
: base(game)
{
}
public override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
shipTexture = Game.Content.Load<texture2d>("FighterSpaceShip");
shipPosition = new Vector2(Artifacts.GamePreferedBufferWidth / 2 - ShipWidth/2, Artifacts.GamePreferedBufferHeight - ShipHeight);
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
public override void Update(GameTime gameTime)
{
KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Up))
shipPosition += new Vector2(0, -3);
if (keyboardState.IsKeyDown(Keys.Down))
shipPosition += new Vector2(0, 3);
if (keyboardState.IsKeyDown(Keys.Left))
shipPosition += new Vector2(-3, 0);
if (keyboardState.IsKeyDown(Keys.Right))
shipPosition += new Vector2(3, 0);
if (!GraphicsDevice.Viewport.Bounds.Contains(GetBounds()))
{
Rectangle screenBounds = GraphicsDevice.Viewport.Bounds;
if (shipPosition.X < screenBounds.Left)
{
shipPosition.X = screenBounds.Left;
}
if (shipPosition.X > screenBounds.Width - ShipWidth)
{
shipPosition.X = screenBounds.Width - ShipWidth;
}
if (shipPosition.Y < screenBounds.Top)
{
shipPosition.Y = screenBounds.Top;
}
if (shipPosition.Y > screenBounds.Height - ShipHeight)
{
shipPosition.Y = screenBounds.Height - ShipHeight;
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
SpriteBatch spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
spriteBatch.Begin();
spriteBatch.Draw(shipTexture, shipPosition, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
public Rectangle GetBounds()
{
return new Rectangle((int)shipPosition.X, (int)shipPosition.Y,
ShipWidth, ShipHeight);
}
public void RestSpaceShip()
{
shipPosition = new Vector2(Artifacts.GamePreferedBufferWidth / 2 - ShipWidth / 2, Artifacts.GamePreferedBufferHeight - ShipHeight);
}
}
as you can see the update and draw method of class, update is accepting user input from keyboard which will help spcae ship to move. Also notice that update method is not letting the spce ship go out of screen. Draw method is drawing space ship on screen.
Same way we can create meteor component. Please find below code for that.
public class Meteor : Microsoft.Xna.Framework.DrawableGameComponent
{
Vector2 meteorPosition = Vector2.Zero;
Vector2 meteorVelocity = Vector2.Zero;
Texture2D meterorTexture;
Random random;
const int MeterorHeight = 56;
const int MeterorWidth = 64;
public Meteor(Game game)
: base(game)
{
}
public override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
meterorTexture = Game.Content.Load<texture2d>("meteorImg64");
random = new Random(this.GetHashCode());
base.LoadContent();
}
protected override void UnloadContent()
{
base.UnloadContent();
}
protected void UpdateMeteorPosition()
{
meteorPosition.X = random.Next(Game.Window.ClientBounds.Width - MeterorWidth);
meteorPosition.Y = 0;
meteorVelocity.Y = 1 + random.Next(7);
meteorVelocity.X = random.Next(7) - 1;
}
public override void Update(GameTime gameTime)
{
if (!GraphicsDevice.Viewport.Bounds.Contains(new Rectangle((int)meteorPosition.X, (int)meteorPosition.Y, meterorTexture.Width, meterorTexture.Height)))
{
UpdateMeteorPosition();
}
meteorPosition += meteorVelocity;
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
SpriteBatch spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
if (meteorPosition == Vector2.Zero && meteorVelocity == Vector2.Zero)
UpdateMeteorPosition();
spriteBatch.Begin();
spriteBatch.Draw(meterorTexture, meteorPosition, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
public bool CheckCollision(Rectangle rect)
{
Rectangle spriterect = new Rectangle((int)meteorPosition.X, (int)meteorPosition.Y, MeterorWidth, MeterorHeight);
return spriterect.Intersects(rect);
}
}
as you can notice we are randomly creating a meteor and keep it moving on screen with its velocity which is randomly decided.
Finally we can create our game1.cs class which will join these componants and keep updating the game.
public class SpaceGame : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D galaxyBackImage;
SpaceShip ship=null;
const int MeteorCount = 5;
const int MeteorUpdateTime = 10000;
private int lastTickCount;
int rockCount = 0;
public SpaceGame()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = Artifacts.GamePreferedBufferWidth;
graphics.PreferredBackBufferHeight = Artifacts.GamePreferedBufferHeight;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Services.AddService(typeof(SpriteBatch), spriteBatch);
galaxyBackImage = Content.Load<texture2d>("BGI_galaxy");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
KeyboardState keyboard = Keyboard.GetState();
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || (keyboard.IsKeyDown(Keys.Escape)))
this.Exit();
if (ship == null)
{
StartGame();
}
UpdateGame();
base.Update(gameTime);
}
protected void UpdateGame()
{
bool hasColision = false;
Rectangle shipRectangle =ship.GetBounds();
foreach (GameComponent gc in Components)
{
if (gc is Meteor)
{
hasColision = ((Meteor)gc).CheckCollision(shipRectangle);
if (hasColision)
{
RemoveAllMeteors();
StartGame();
break;
}
}
}
CheckforNewMeteor();
}
private void CheckforNewMeteor()
{
if ((System.Environment.TickCount - lastTickCount) > MeteorUpdateTime)
{
lastTickCount = System.Environment.TickCount;
Components.Add(new Meteor(this));
rockCount++;
}
}
private void RemoveAllMeteors()
{
for (int i = 0; i < Components.Count; i++)
{
if (Components[i] is Meteor)
{
Components.RemoveAt(i);
i--;
}
}
}
protected void StartGame()
{
for (int i = 0; i < MeteorCount; i++)
Components.Add(new Meteor(this));
if (ship == null)
{
ship = new SpaceShip(this);
Components.Add(ship);
}
ship.RestSpaceShip();
lastTickCount = System.Environment.TickCount;
rockCount = MeteorCount;
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(galaxyBackImage, new Rectangle(0, 0, graphics.GraphicsDevice.DisplayMode.Width, graphics.GraphicsDevice.DisplayMode.Height), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
public class Artifacts
{
public const int GamePreferedBufferHeight=600;
public const int GamePreferedBufferWidth=800;
}
as you can see we have added componants in our game.
Let's understand some basics about these classes.
GraphicsDeviceManager is responsible for drawing objects on your screen. Its created and added into our game1.cs class.
SpriteBatch will be responsible for drawing images on screen. It will accept an graphic device object. SpriteBatch will have a Draw method for drawing images and DrawString method for drawing texts.
As you can see in code SpriteBatch accepting a Texture2D object which is nothing but out image, a position of image where to draw it on screen.
Its very simple code, you can directly copy paste it and use in your project. There is some method in meteor class for colision detection with space ship too.
You can dig deep copy paste code and explore it.
Till then Happy Coding.
Points of Interest
Its awesome fun developing games, I love exploring each and every item.
I learnd all these stuff from Begining XNA 3.0 Game Programing book by Alexandre Santos Lobão, Bruno Evangelista,José Antonio Leal de Farias and Riemer Grootjans.
I got the game idea from book only.
History
19th September 2012 : Added Basic Structure of Fighter Space Ship Game.