Creating an XNA project in 10 minutes (give or take)

First, open Visual Studio 2008 Express (available in the labs, or downloadable from Microsoft if you are working from home). Select New Project from the file menu, and select a Windows game from XNA. Give it an approprate name (we'll use BouncingBall for this example), and save it in an appropriate location (like your home directory on the network drive)

Selecting a new project

 

Visual studio will create a nice project, with some default files aready filled in:

Initial Project

 

We have two .cs source files, and a bit of directory structure for storing our art assets. Our main program just creates a new Game object and calls the run method on it, while the Game object itself is pretty straightfoward:


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 BouncingBall
{
    /// This is the main type for your game
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// 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.
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        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
        }

        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// param "gameTime" Provides a snapshot of timing values.
        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);
        }

        /// This is called when the game should draw itself.
        /// param gameTime Provides a snapshot of timing values.
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }
    }
}

Unforuneatly, we can't see the complete picture, since the source for the underlying Microsoft.Xna.Framework.Game class is not available. The main game loop, however, is pretty straightforward:

 

When the game is run:

So, all we need to do now is put in code to load any necessary content, update the world, and draw the world. First up, we will create some content. Open up your favorite graphic editing software (we'll use Gimp, which is on the labs, but there are also versions of photoshop on the lab machines), and create a new image. Be sure to go to the advanced options, and fill with transparency:

Gimp Create new image screenshot

We'll zoom out a bit, and then create some content:

Gimp Screenshot

Save the file as ball.png, wherever you'd like on your hard drive (while we will move it into the approprate project in a moment, it is probably best to alwasy save on your network drive). Once the image is saved, open the folder containing the image, and drag it into the content folder in the containing folder, and drag the image right into the content section of the project explorer in visual studio

Dragging Content

Dragging the file to the content directory copies it to the appropriate content subfolder, and makes it availabe to XNA. We can have more complex data heirarchies, but for now we will leave everything flat.

Now we can add a new instance variable to our class

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D mBallTexture;  // Added instance variable
     ... (rest of the class defintion)

And in load content, we can load up this texture:

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            mBallTexture = Content.Load<Texture2D>("ball");
        }

Now we can display the content in the draw method. To draw a spite on the screen, we call the begin method on the sprite object, then call as many draw calls as we'd like, and the call the end method. Drawing can be quite complicated, but we will be simple for now

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            spriteBatch.Begin();

            spriteBatch.Draw(mBallTexture, new Vector2(100, 100), Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
The first parameter to the Draw method is the actual texture to draw, the second parameter is the postion on the screen to draw the texture, and the third parameter can be used to alter the color of the sprite (White means that we are not doing any alteration of the color)

Now, if we run our program, we get:

Selecting a new project

Of course, this isn't very interesting -- le'ts try to add a little movement. We can create Vector2 instance variables for the position and velocity of the ball, and update them every frame:

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            position = position + velocity * gameTime.ElapsedGameTime.Milliseconds;
            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// This is called when the game should draw itself.
        /// param name="gameTime" Provides a snapshot of timing values.
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            spriteBatch.Begin();

            spriteBatch.Draw(mBallTexture,position, Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }  

When of course, we will need to initialize the values for position and velocity, which we can do in the initializaion section of the code

            mVelocity = new Vector2(0.1f, 0.3f);
            mPosition = new Vector2(0, 0);

Note that since the constructor for Vector2 takes floating point numbers, and floating point literal constants are double by default, we need to specify that we want float literals (else it wouldn't compile).

OK, so now we have a ball that moves off the screen -- not too exciting. How could we get it to bounce off the corners? First of all, we need to know where the edges of the screen are. We'll go ahead an set up the screen size, by requesting 720p (so that it will work nicely on the Xbox). In the constructor of our game:

        private const int BackBufferWidth = 1280;
        private const int BackBufferHeight = 720;


        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = BackBufferHeight;
            graphics.PreferredBackBufferWidth = BackBufferWidth;
            Content.RootDirectory = "Content";
        }

Now, when we get too far past the edge of the screen, we can bounce:

        protected override void Update(GameTime gameTime)
        {

            position = position + velocity * gameTime.ElapsedGameTime.Milliseconds;

            if (mPosition.X + mBallTexture.Width > BackBufferWidth || mPosition.X < 0)
            {
                mVelocity.X = -mVelocity.X;
            }
            if (mPosition.Y + mBallTexture.Height > BackBufferHeight || mPosition.Y < 0)
            {
                mVelocity.Y = -mVelocity.Y;
            }
            base.Update(gameTime);
        }

Or, we could make our ball circle on the sceen instead:

        protected override void Update(GameTime gameTime)
        {
            mCurrentAngle += gameTime.ElapsedGameTime.Milliseconds * RadiansPerMilisecond;
            mPosition = mCenter + new Vector2(mRadius * (float)Math.Sin(mCurrentAngle),
                                              mRadius * (float) Math.Cos(mCurrentAngle));
            base.Update(gameTime);
        }


 
Of course, we would also need to add (and initialize) the instance variables mCenter and mRadius, as well as the constant RadiansPerMilisecond for this to compile) OK, so now you have the basics of how to create with XNA. The software engineer in you should be screaming that instance variables in the Game class are essentially global variables, and exposing low-level details in the main game loop is the path to of madness -- and you would be perfectly correct. More on how to structure your program later ...