Windows 8 Game Development using C#, XNA and MonoGame 3.0: Building a Shooter Game Walkthrough – Part 2: Creating the Shooter/Player Asset of the Game
Overview
The Shooter game from the XNA Game tutorial is a particular type of game with a set of well-defined limits around user interaction. Given these well-defined parameters we can leverage touch aspects of Windows 8 as well as other forms of user interaction for the user in playing the Shooter Game. In leveraging the XNA Framework, we find that the framework Game class implements a basic design using the game loop concept. With this concept, XNA provides not only a base window to display the game, but also provides overloadable methods that a game implements to facilitate communication between your game and the operating system. We will discuss more details around XNA game development and resources throughout this walkthrough. In Part 2 of this series, we will build the code and class to Draw a player character i.e. Shooter on the screen and add the code needed to receive input and move the player around. For an overview of MonoGame and installation information, please see Part 1 of this Blog Series Part 1: Overview, Installation, MonoGame 3.0 Project Creation.
Creating the Shooter
Step 1 – Create the Player Class
Start Visual Studio 2012, and open the Win8ShooterGame solution that was created in Part 1 of this series. Currently this solution contains a blank MonoGame/XNA project that when run displays the default XNA Cornflower blue screen, as shown below.
Select the Win8ShooterGame project. Add a new class to your project by pressing SHIFT + ALT + C or right click on the Win8ShooterGame project and click Add New Item and selecting a Class. Name the class by typing in Player.cs. Press ENTER. A brand new code file will be created and a code window will open up. This file will contain all the code we'll write to define the player class. This includes all the data and functions that describe what the shooter/player will do within the constructs of the Shooter game. We'll start with basic values such as position, and add a few functions we can call continuously to draw the player on the screen. Additionally, later in this walkthrough we will add functions later move the player around later.
Once the Player.cs file is created, the default class created will show the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Win8ShooterGame
{
class Player
{
}
}
Since we need access to the XNA framework and associated functionality, we need to add the using statements to the class for the XNA framework. Therefore all the following code shown below to the end of the list of using statements in the Player class file. You have the option to remove all of the using statements placed in the class object by default Except the using System, as we will not being using any of those class objects for the Player class. Also let's change the namespace to better represent the player class object by changing the namespace from Win8ShooterGame to Shooter.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Shooter
{
class Player
{
}
}
Now within the class Player definition, let's add the stub for the methods that will be used by the game to setup, update, and draw the Shooter player within the game. Add the following code shown below to your Player class.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Shooter
{
class Player
{
public void Initialize()
{
}
public void Update()
{
}
public void Draw()
{
}
}
}
Now let's add some variables to can store player data and information needed to ensure we can create and update the Shooter player accurately. Look for the first { mark under class Player, and enter the following lines:
// Animation representing the player
public Texture2D PlayerTexture;
// Position of the Player relative to the upper left side of the screen
public Vector2 Position;
// State of the player
public bool Active;
// Amount of hit points that player has
public int Health;
// Get the width of the player ship
public int Width
{
get { return PlayerTexture.Width; }
}
// Get the height of the player ship
public int Height
{
get { return PlayerTexture.Height; }
}
Now let's write the code to setup the Shooter player's starting position, set the graphic (texture), set the player status, and finally set the Health of the player. To do this, we add code to the Initialize method we created in the Player class object. Change code of the Initialize method to add the code showing below:
public void Initialize(Texture2D texture, Vector2 position)
{
PlayerTexture = texture;
// Set the starting position of the player around the middle of the screen and to the back
Position = position;
// Set the player to be active
Active = true;
// Set the player health
Health = 100;
}
Now that we have initialized the player by setting base values associated with the player object, we can now use these to Draw the player on the screen using the position and the graphic (Texture2D). To draw the graphic we must draw the sprite (asset) by queuing Texture for rendering. We'll do this by passing our graphic (texture) to SpriteBatch object within the Draw method. Change the Draw() method inside the Player class by adding the code below and changing the method by adding the parameter of a SpriteBatch. Please see the following code:
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(PlayerTexture, Position, null, Color.White, 0f, Vector2.Zero, 1f,
SpriteEffects.None, 0f);
}
We have now defined what a "Player" at a very basic level by creating a class that has all the data and methods needed to create a Shooter player. The next step will be to create a Player object in the context of the Game loop in order to utilize the player object as a Shooter in the game.
Step 2 – Instantiate the Player object in Main Game class
Switch over to Game1.cs by double-clicking "Game1.cs" in the Solution Explorer. Game1.cs is a very important code file - it is already partially filled out, as you will see. This code is our game loop. We're going to be making some additions to this file to make the Player class we've created part of the game loop. When we do this, it will then start to draw on the screen, every frame. Start at the top of the code, and underneath the using Microsoft.Xna.Framework.Graphics, add the following namespace:
using Shooter;
Continue down and find the string marked public class Game1 : Game. A few lines down, below SpriteBatch _spriteBatch, add these lines:
// Represents the player
Player player;
Look down the code, find the method called protected override void Initialize(). Inside that method, underneath the TODO comment, add these lines:
// Initialize the player class
player = new Player();
Next, we have to load the player graphic and set the player's initial position before we can draw them on the screen. This is where we'll call the Initialize method of our Player class. Since this involves loading a graphic from disk, we will do this inside the game loop's LoadContent() method. Look down the code, find the method called protected override void LoadContent() . Inside that method, below the SpriteBatch assignment operator and the TODO comment, add these lines:
// Load the player resources
Vector2 playerPosition = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y + GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
player.Initialize(Content.Load<Texture2D>("Graphics\\player"), playerPosition);
We are ready to draw our player. Any time you draw something, you'll draw it via the game loop's Draw() method. Look down the code, find the method called protected override void Draw(GameTime gameTime). Inside that method, below GraphicsDevice.Clear(Color.CornflowerBlue) and the TODO comment ; add these lines:
// Start drawing
_spriteBatch.Begin();
// Draw the Player
player.Draw(_spriteBatch);
// Stop drawing
_spriteBatch.End();
We have now completed the code to draw/render the player object. Please review the Begin() and End() function calls, and note that any additional drawing and/or rending of objects will be added and completed between the Begin() and End() functions.
Let's draw the player on the screen. Add a folder to the Win8ShooterGame project called Content, then add a folder underneath the Content folder called Graphics. Download the precompiled shooter graphic, player.xnb, from the following link: https://sdrv.ms/Rmc11V to your computer. Right click the Graphics folder within the project and select the menu option to Add an Existing item. Add the player.xnb file from the location you saved the file on your computer. Now we need to set the properties for this graphic. Right click the newly added file, player.xnb. Under the Properties option, set Build Action to property to Content and Copy to Output Directory property to Copy Always.
Now build and run your game by either via selecting Local Device or and the Windows Simulator via Build option. If successful, you will see the Cornflower Blue background with the Ship (player) shown on the screen.
Figure 1 Ship/Player Drawn on the Screen
You now have created your Shooter player and displayed it on the screen. In this walkthrough, I provided a compiled player.xnb graphic in order to display the player on the screen. In Part 3 of this series, we remove the precompiled player graphic and walkthrough how add graphics and sound for the Shooter game by building a Content Pipeline using Visual Studio 2012 / Visual Studio 2010 using the XNA SDK for XBOX or Windows Phone. We then will compile the Content Pipeline and show how to add the graphics resources created from the XNA Content Pipeline to the MonoGame Shooter project.
Comments
Anonymous
December 21, 2012
Thanks for making this great tutorial. Just wanted to point out an issue I ran into with importing the player.xnb content. In order for the code to work for me, I first needed to create a folder named 'Content' and then a folder named 'Graphics' within content. Structure ended up looking like this: Win8Shooter -Content -Graphics player.xnbAnonymous
December 21, 2012
Hi Johnathan: Thanks for the catch! I obviously got ahead of myself given that in Part 3 of this tutorial,"Creating a content pipeline for MonoGame" I will have the Content folder created and two folders underneath. I will update the blog so that either it notes the Content folder creation or change the code to look at the Graphics folder alone. Which do you think is best? BTW: I will post Part 3 this afternoon/evening.Anonymous
December 21, 2012
I like the idea of the Content folder with Graphics inside it. Will help lead people into having organized projects if they build off the tutorial to make a game. Looking forward to Part 3! Perfect timingAnonymous
December 23, 2012
Is there any way to use a .png asset instead of the .xnb?Anonymous
December 29, 2012
Just noticed that I had to change the build action of the player graphic to "content" for it to work. Might be obvious to others but I'm a newbie... Great tutorial so far, looking forward to part 3.Anonymous
January 08, 2013
Guys: Part 3 is posted. Neil: This addresses your question about the folders.Anonymous
January 21, 2013
T E W - thank you for this detailed tutorial. Good job! I can use this information for my project.Anonymous
January 23, 2013
The comment has been removedAnonymous
January 23, 2013
TZ: Under properties for the Graphics folder, the file: player.xnb --> Set Build Action to property to Content and Copy to Output Directory property to Copy Always. Did you have this set already?? Let me know if this works for you, if not we can investigate further. I am glad you asked this question, given I have been working to Post Part 4, I haven't come back to Part 2 to update this and correct my leaving out the folder structure part. I will do this now.Anonymous
January 26, 2013
Thanks T E W for this tutorial walkthrough series. Good work. I look forward to seeing more of this kind of step-by-step documentation on Windows 8 MonoGame development available in the near future.Anonymous
March 29, 2013
Great! Can't wait for Part 3!Anonymous
March 29, 2013
Anthward: Part 3 and 4 are posted. I updated the link is this blog for you.Anonymous
March 30, 2013
The comment has been removedAnonymous
August 27, 2013
I have had the issue TZ did. A bunch of errors about player object not being initalized. If anyone else runs into this, all you have to do is put player = new Player(); BEFORE base.initialize(); in protected override void Initialize (), in Game1.csAnonymous
October 26, 2013
Just wanted to mention that I just set up my development environment today, and in the version of the base project that I have, the spriteBatch object is created without an underscore. No problem, I just removed the underscore from those lines in the Draw function. Thanks for writing these tutorials. I'll be going right through them... :-)Anonymous
November 08, 2013
As JackieChan mentioned before: "Is it possible to load .PNG or .TGA" instead of .XNB ? I know you can just load a .PNG in but it isn't transparent. You should explain how to that too. .PNG is much better known then .XNBAnonymous
November 11, 2013
StefanJanssen & JackieChan: Look at Part 3 to answer your question about different types of graphic files.Anonymous
April 20, 2014
The comment has been removedAnonymous
April 21, 2014
@Gregory: TZ: Under properties for the Graphics folder, the file: player.xnb --> Set Build Action to property to Content and Copy to Output Directory property to Copy Always. Did you have this set already?? Let me know if this works for you, if not we can investigate further. Also make sure you have player = new Player() before inititalize.Anonymous
September 23, 2015
"Additionally, later in this walkthrough we will add functions later move the player around later." What?Anonymous
January 19, 2016
Hi just wanted to say that this works with VS 2015 Community. And note that the two things people point out still needs to be corrected: _spriteBatch should be spriteBatch (no underscore) player=new Player(); - must be first statement in Initialize method before the call to base.Initialize()