XNA Game Studio and game development with
the Xbox LIVE Hub are major features of Windows Phone 7. The XNA
Framework for Windows Phone is part of XNA Game Studio 4.0, which is a
plug-in for Visual Studio 2010 that enables developers to create games
for Windows, Xbox and now Windows Phone 7.
The XNA Framework enables developers to write
applications, primarily games, using managed .NET Framework code. The
XNA Framework is consistent across the target platforms mentioned
previously. Applications targeting a specific platform will have unique
user input capabilities, such as the mouse and keyboard for the
desktop, Xbox controller for Xbox and on the desktop if a USB
controller is connected. For Windows Phone 7, the primary input is the
touch screen and sensors. Otherwise, much of the code for a
cross-platform game would be exactly the same.
1. Hello XNA for Windows Phone
When you install the Windows Phone Developer Tools
it includes XNA Game Studio, with a dedicated template folder XNA Game
Studio 4.0 in the Visual Studio 2010 New Project dialog to create
either a Windows Phone game or a Windows Phone game library assembly.
All game development is done non-visually through
code. You do not use Expression Blend to create games unless building
the game experience in Silverlight. This makes the Emulator that much
more important for XNA Framework game development. The good news is
that the Windows Phone Emulator is hardware accelerated on the Windows
Vista or Windows 7 development machine, enabling a great game
development experience with the emulator to visually see the game in
action without having to always deploy to a device.
Right-click on the solution explorer and select Add... => New Project, select Windows Phone Game (4.0), and then type HelloXNA
as the project name. Be sure to right-click on the new HelloXNA project
and set it to the startup project for the solution if is not already.
After the project is created, you can see that the project layout is very different from a Silverlight project, as shown in Figure 1.
Notice in Figure 1
there are actually two projects listed, HelloXNA and HellXNAContent.
The primary project with the output remains the HelloXNA project. The
HelloXNAContent project is the contentproject for the HelloXNA project,
which I cover in the next section.
1.1. Game Content
As noted in the previous paragraph, the content
project is where the content is located – the sprites, textures, 3D
models, and so on for the game. Sprites and textures generally refer to
2d images you move around the screen (sprites) and the background or
surface image (textures). In our sample we create three simple .tga
files to represent a background texture for the simple game, a
spaceship sprite, and a hero ship sprite that the user controls and a
missile sprite that is fired from the hero ship. Figure 2 shows the content project layout, as well as the properties for the hero ship sprite.
Notice in Figure 2 that the heroship.tga image file has an AssetName, a Content Importer and Content Processor properties. The Content Importer and Content Processor
property automatically selected when the content is added. Internally,
the XNA Framework stores content assets in a custom compressed format
so it uses content importers and processors to import external content
into the internal format. XNA Game Studio ships with several built-in
converters for common content listed here, with explanations for the
less than obvious converters:
Effect: DirectX High Level Shader Language (HLSL) .fx file (not supported on WP7)
AutoDesk FBX: .AutoDesk file format for three dimensional models
Sprite Font Description
MP3 Audio File
Texture: Essentially a bitmap
WAV Audio File
WMA Audio File
WMV Video File
XACT Project: XACT is a DirectX audio tool for building rich game audio
X File: DirectX 3D model file
XML Content
You can create custom content importers as well as
purchase third-party converters for file formats not available out of
the box. However, in most cases the previous list supports the vast
majority of content and content creation tools available.
The other property for content is the AssetName, which is based on the filename without the extension. When you load content into your game you load it via the AssetName property, as you will see shortly.
Make friends with a graphic artist if you are not
very artistic. Content is just as important, if not more so then the
coding in a game. There are third-party content providers that sell
content you can tweak as well as higher graphic artist talent on a
contractual basis. Programmer art won't cut it.
|
|
1.2. The Game Loop
Let's continue to explore the code and functionality in the HelloXNA
project by exploring the default game loop code. When learning to build
games, development centers on the game loop summarized here:
Load the game content and related objects.
Update the object's state.
Draw the object to the screen.
The XNA Framework provides a typical game loop
development model consisting of initial content load, followed by
repeated calls to the update, and draw methods. By default the XNA
Framework game loop is fixed-step game loop at 30 frames per second
with each frame represented by calls to draw and update. It is set to
30 frames per second (fps)to be aligned with the refresh rate of the
hardware. You can change the frame rate to 60 fps using the following
code:
GraphicsDeviceManager.SynchronizeWithVerticalRetrace = false;
game.TargetElapsedTime = FromSeconds (1/60f);
However, if you increase the frame rate, it will
impact battery performance with possibly minimal tangible benefit. One
way around this is to call update twice per each draw call by creating
a custom game loop. This would be the recommended course of action over
adjusting the frame rate above 30 frames per second.
Now let's dive in to the code. When we created the HelloXNA game project, it generates a code file Game1.cs, which is the main code file and includes the game loop logic. Listing 1 has the full code listing for reference.
Example 1. Generated Game1.cs
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.Input.Touch; using Microsoft.Xna.Framework.Media;
namespace HelloXNA { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch;
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content";
// Frame rate is 30 fps by default for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks(333333); }
/// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here
base.Initialize(); }
/// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here }
/// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() {
// TODO: Unload any non ContentManager content here }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();
// TODO: Add your update logic here
base.Update(gameTime); }
/// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime); } } }
|
Listing 1
is insightful reading to help you understand the game loop
implementation in XNA Game Studio. The comments help you understand
what to do where in the game loop code but we briefly cover the methods
here starting with the constructor for Game1 in Listing 1. The constructor initializes a reference to the GraphicsDeviceManager, which represents the graphics device. It also sets the content root directory to the Content folder, which is where all of our content will reside. Finally it sets the frame rate to 30 fps.
The Initialize() method is where developers
query for required game services. Game services are objects defined by
a custom Interface you create that you want to access for the entire
life of the game. It is a way to expose an object, such as a 3D camera
object, to many other objects.
I'm sure you can guess what the LoadContent()
method does. It is called once per game with the idea that you load all
of your content upfront so as to not impact the game loop timing by
loading content on the fly in the middle of a frame.
For a game with a lot of content, this may not make
the best use of resources. In this case, the game can be broken up into
levels and a developer can dynamically load content at the start of
each level. Users won't mind waiting a few seconds up front as the
level loads, as long as the return is better game play during the level
by pre-loading the content.
After loading the content in the LoadContent method, the next method in Listing 1 is the UnLoad method. While you have to explicitly load content in LoadContent, the opposite is not required. Any content that you load in the LoadContent
method is automatically managed by XNA Framework. However, for any
content that you load dynamically and that is not explicitly managed by
a ContentManager object. An example object is a DynamicVertexBuffer that requires the Dispose() method to be called. Otherwise, content that is loaded by ContentManager will automatically be unloaded either when the game exits or if a developer manually removes a GameComponent object. A GameComponent
is an XNA Framework feature that allows a developer to encapsulate a
complex game object into the game loop in an object oriented way.
As mentioned, the Update() and Draw() methods are the heart of the game loop. The default Update
method checks to see if the user pushes the hard key Back button on the
Windows Phone 7 device. If so, the game exits. The other code calls base.Update(gameTime) to allow the minimum game loop logic to occur. The Update method takes one parameter of type GameTime. The GameTime
type contains a snapshot of game timing state that can be used by
variable step (real time) or fixed-step (game time) games. The GameTime object has three properties all of type TimeSpan:
ElapsedGameTime: The amount of time since the last call to the Update method.
IsRunningSlowly: A Boolean value. If it has a value of true, this indicates that the ElapsedGameTime is running longer than the TargetElapsedTime
for the game loop. The game should do something to speed up processing
in the Update method such as reducing calculations; otherwise the game
frame rate will potentially decrease by skipping calls to the Draw method.
TotalGameTime: The amount of time since the start of the game.
Developers can use these values to perform
game-related calculations, such as when a grenade object should explode
after it was initially tossed, as an example.
When developing a game, always keep in mind that
games, videos, movies, and so on all depend on tricking the human eye
into believing that it is watching continue motion. In general, 30 fps
is the minimum before the human eye starts to perceive that it is not
watching continuous motion. I mentioned the two types of game loops,
fixed-step and variable step. The type of game loop affects how a
developer manages the user perception of motion, which we dig into in
the next two sections.
1.2.1. Fixed-Step Game Loop
A fixed-step game loop tries to call its Update
method at a regular interval, providing a fixed chunk of time for the
developer to perform calculations in Update before drawing the scene.
The fixed-step game loop is the default for XNA Framework. For the Xbox
and Windows, the default frame rate is 60 fps in a fixed-step game
loop, which means that Update is called every 1/60 of a second.
For Windows Phone 7, the default frame rate for a
fixed-step game is 1/30 of a second, which aligns with the hardware
screen refresh rate. Visually, a higher frame rate does not provide any
benefit, but it would impact battery life more.
Based on this information, the value TargetElapsedTime from the gameTime parameter for Update (and Draw) will have a value of 1/30 of a second for the value of its TimeSpan. The Update and Draw methods are called every 1/30 of a second, unless IsRunningSlowly returns true. In that case, the call to Draw is skipped so that Update catches up, resulting in a reduced frame rate.
NOTE
When the game pauses in the debugger, the Update method is not called until the debugger resumes the game.
1.2.2. Variable-Step Game Loop
In this type of game, Update and Draw are called continuously without regard for the value set to the TargetEllapsedTime
property resulting in a variable frame rate. With the fixed refresh
rate for the screen of 30 fps, there may not be much gained by a
viable-step loop without potentially negatively impacting battery
performance.
Now that you have background on XNA Game
Studio development, how content is loaded, and the game loop, let's
dive in and create a simple game.