Jump to content

The XNA Tutorial - Part 1

- - - - -

This topic has been archived. This means that you cannot reply to this topic.
5 replies to this topic

#1
semprance

semprance

    Programmer

  • Members
  • PipPipPipPip
  • 126 posts

XNA Tutorial – Part 1

*Welcome to my XNA tutorial! The aim of this tutorial (and the ones to follow) is to build a clone of the classic game Pong using C# and XNA.
So let’s start with the obvious question that some of you are asking: What is XNA? XNA is a set of tools and libraries built to work with the .NET Framework and, in particular, with the C# programming language. It contains libraries for dealing with all the different elements of games: graphics, sound, video, input, content management, and so on. I could go on, but if you want more information you should check out the XNA Wikipedia page or the XNA Creator’s Club homepage for more information.


Getting Set Up


So before we get started you’ll need to get set up. Now, I could go in to great detail about how to install and set up Visual Studio to work with XNA, from scratch, but I’m not going to. This is because I’m assuming the following facts:



  • You have Visual Studio installed.

  • You have a strong understanding of basic programming concepts – types, expressions, methods, classes, etc.

  • You have some or a little understanding of advanced programming concepts – for this particular tutorial, inheritance, though in later tutorials you will need to understand polymorphism and other advanced “OO” concepts.

  • You have Visual Studio or Visual C# Express installed (I personally will be using Visual Studio Professional 2008).

  • You’ve never used XNA before.


With that said the first thing you’ll need to do is download XNA Game Studio from here:
XNA Creators Club Online - downloads


At the time of writing, XNA Game Studio 3.1 is the latest version. Additionally, check which one you’re downloading as specific versions are only compatible with certain platforms; For example, currently XNA Game Studio 4.0 is only compatible with the Windows Phone 7, so don’t download that one!


Once you’ve downloaded it, run the installer. Again I’m not going to explain how: if you managed to install Visual Studio then I’m sure you’ll have no trouble with this.
Once you’re installed and rebooted and whatever else, you’ll need to create an XNA project:

  • Open up your version of Visual Studio.
  • From the menu bar, select File, then New, and then Project.
  • Select the arrow next to ‘Visual C#’ then select ‘XNA Game Studio x.x’ (where x.x is the version number).
  • In the box to the right, select ‘Windows Game (x.x)’.
  • Name the project and solution ‘PongTutorial’ (or whatever you want for that matter, I’m not fussed), and select the Location you want to save it.
  • Select the ‘OK’ Button.

Voila, your project is created. Now that the easiest (yet most tedious) bit is over we can start creating our game!


I’m Not An Artist


I’m providing assets for this game purely because it’s a formality. The assets consist of two png images: a paddle and a ball. One is a white square and the other is a white rectangle so please, feel free to draw your own. If you’re that lazy, you can download the zip of the finished project at the bottom of this post. Inside there is a folder called ‘Resources’ that contains the assets that I used when creating this tutorial. Just copy them out somewhere ready for the next step.


Check that you have the Solution Explorer open; it’s usually on the right and contains a list of the projects, folders and files in your solution. In the Solution Explorer, right-click ‘Content’, highlight ‘Add’ and click ‘Existing Item...’


Now navigate to the folder on your hard-drive containing the aforementioned resources (the ball and paddle images), highlight them both, and click ‘Add’.


Hey Presto! Our assets have been added (yep, it’s that simple).

Can We Start Coding Now?


No. Not quite yet, but we are going to start looking at some code. Namely the Game1.cs file in our project. If it’s not open, double click it in the Solution Explorer. Briefly scroll through the code and read the comments (if you can’t be bothered then just keep reading).


The Game1 class is the lowest level of our game. It’s the set on which our game will be created. There are a number of methods to take note of but only two that are really, REALLY, important: Update and Draw. These two methods are the basis for the running of the whole game.



Update: The Update method is where we put all the information that we want to record and change between frames, for example, character positions, user input, the playing of sounds, the loading of content, etc.


Draw: The Draw method is where we draw our assets to the screen. In the case of this tutorial, we will be drawing only three things to the screen: the ball, the players paddle, and the computers paddle.
Both of the above methods are run once per frame and a frame occurs roughly once every 60th of a second (in game speak, 60 fps – frames per second) depending upon system performance.


There are a few other methods to: Initialize, LoadContent, the class constructor, and so on. These all perform the obvious tasks implied by their names and you can read a succinct description in the comments above each of them.


Now that we’ve had a good look at the Game1 class, you can close it. I actually lied a bit earlier when I said this was the set for our game. Still, it’s important for you to get to know this class and its method because they’ll be cropping up a lot later.


Yes, Now We Can Start Coding?


Right, on to the good stuff now it’s time to start coding. The first thing you’ll need to do is add a new class file to the project named ‘GameScreen.cs’.


Once this file is added you should have a file that looks something like this:



[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System;[/FONT]

[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System.Collections.Generic;[/FONT]

[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System.Linq;[/FONT]

[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System.Text;[/FONT]

[FONT="] [/FONT]

[COLOR=blue][FONT="]namespace[/FONT][/COLOR][FONT="] PongTutorial [/FONT]

[FONT="]{[/FONT]

[FONT="] [COLOR=blue]class[/COLOR] [COLOR=#2B91AF]GameScreen[/COLOR][/FONT]

[FONT="] {

}

}[/FONT]



Now, the first thing we need to do is add some ‘using’ statements for some XNA libraries. Add these two statements underneath the other four ‘using’ statements:



[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] Microsoft.Xna.Framework;[/FONT]

[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] Microsoft.Xna.Framework.Graphics;[/FONT]



This will give us access to the classes and method that we need. As a side note, rather than tell you repeatedly, you should just add these two statements to every class file we create during this tutorial. I won’t repeat the code segment over and over, but I will be kind enough to remind you to add the above so just copy them from one class to another to save me some time.


Right, we now have a class with the right references and so on. Now we need our class to inherit from a class within the XNA Framework. This class is named DrawableGameComponent, and it provides a lot of the functionality of the Game1 class we saw earlier, but to individual objects within our game. It is important to note that you shouldn’t ever overuse this class as it is meant to be used sparingly. Moving on, to inherit from this class, change the class declaration statement to this:



[FONT="] [COLOR=blue]class[/COLOR] [COLOR=#2B91AF]GameScreen[/COLOR] : [COLOR=#2B91AF]DrawableGameComponent[/COLOR][/FONT]



This is standard inheritance so it shouldn’t be unfamiliar. Next we need to add the following constructor to the class:



[FONT="] [COLOR=blue]public[/COLOR] GameScreen([COLOR=#2B91AF]Game1[/COLOR] g)[/FONT]

[FONT="] : [COLOR=blue]base[/COLOR](g)[/FONT]

[FONT="] {

}[/FONT]



Again, you should be familiar with the ‘base’ keyword, used for passing parameters from a derived class to an inherited class. Next we need to add some members to our class. Again, members is a term you should be familiar with (sometimes they may be called class variables or declarations or some such other phrase). Above the constructor, insert the following:



[COLOR=blue][FONT="]private[/FONT][/COLOR][FONT="] [COLOR=#2B91AF]Game1[/COLOR] GAME_REF;[/FONT]

[COLOR=blue][FONT="]private[/FONT][/COLOR][FONT="] [COLOR=blue]static[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR] container;[/FONT]



...and in the constructor, add these two lines:



[FONT="] GAME_REF = g;[/FONT]

[FONT="] container = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR]([/FONT]

[FONT="] 0, 0, [COLOR=green]//X & Y[/COLOR][/FONT]

[FONT="] GAME_REF.GraphicsDevice.Viewport.Width, [COLOR=green]//Width[/COLOR][/FONT]

[FONT="] GAME_REF.GraphicsDevice.Viewport.Height [COLOR=green]//Height[/COLOR][/FONT]

[FONT="] );[/FONT]



As you can probably see we now have two members, a Game1 object, and a Rectangle. First of all, I’ll explain the Game1 object. Our Game1 object, when passed to our GameScreen constructor, will be passed as a reference, so by assigning it to our ‘GAME_REF’ variable, our class has access to all the functionality of our Game1 object (we only have one in each game for obvious reasons), such as the GraphicsDevice and the ContentManager and the SpriteBatch and so on. Although this game is small in scope, if you start creating larger games, passing a reference of your Game1 object to most of the classes can be a good idea, especially for classes that have their own Draw and Update methods.



Second, our ‘container’ variable is simply going to be used to store a rectangle representing the Viewport or Screen Area. Although the Game1 class provides access to the dimensions of the Viewport, it can be quite messy to access and so creating a Rectangle to represent it is preferable. Also, the container is static as even though we are only creating one GameScreen currently, if we were to create more, there would be no need to have a ‘container’ variable for each instance of the class (reassigning it in the constructor each time we create an instance has a little overhead so don’t worry about that either). Next, we need to provide easy access to the ‘container’, so add this underneath the constructor:



[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR] Container[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] container; }[/FONT]

[FONT="] }[/FONT]



Again we have encountered a C# feature that you should be familiar with: Properties. This property contains only the ‘get’ property accessor meaning we are only allowing other classes to read the ‘container’ variable, which is exactly what we want. We have also made the property static, like the ‘container’ member, so that any class can access it easily using the line “GameScreen.Container”. Now all our classes have easy access to the dimensions of the Viewport!


The last thing we need to do for this class is add some methods for running the game. These methods are found in the DrawableGameComponents class and so we need to override them. Enter the following between the Constructor and the Container property:



[COLOR=blue][FONT="] public[/FONT][/COLOR][FONT="] [COLOR=blue]override[/COLOR] [COLOR=blue]void[/COLOR] Update([COLOR=#2B91AF]GameTime[/COLOR] gameTime)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]base[/COLOR].Update(gameTime);[/FONT]

[FONT="] }[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]override[/COLOR] [COLOR=blue]void[/COLOR] Draw([COLOR=#2B91AF]GameTime[/COLOR] gameTime)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]base[/COLOR].Draw(gameTime);[/FONT]

[FONT="] }[/FONT]



If you’re using intellisense then a list of methods including these two should appear after you type the word ‘override’ so you can select them from there.

The Object Of The Game


Awful subtitle puns aside, we need to make some objects for a game. Except I’m lying, because before we do that we need to create a separate base class to underlie them. Now, create a new class file and name it GameEntity.cs (the class should be called GameEntity and don’t forget to add the ‘using’ statements we talked about earlier). First we need to make a simple change to the class. Change the declaration to the following:



[FONT="] [COLOR=blue]abstract[/COLOR] [COLOR=blue]class[/COLOR] [COLOR=#2B91AF]GameEntity[/COLOR][/FONT]



By doing this we have made the class abstract (duh...) meaning that this class may be inherited classes or may have its static members accessed, but cannot be instantiated directly. Of course you already know this so I need not explain any further ;-) Next we need to add a multitude of members and declarations. Add the following to the body of the class:



[COLOR=blue][FONT="] protected[/FONT][/COLOR][FONT="] [COLOR=#2B91AF]Texture2D[/COLOR] sprite;[/FONT]

[COLOR=blue][FONT="] public[/FONT][/COLOR][FONT="] [COLOR=#2B91AF]Texture2D[/COLOR] Sprite { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] [COLOR=blue]this[/COLOR].sprite; } } [/FONT]

[FONT="] [COLOR=blue]protected[/COLOR] [COLOR=#2B91AF]Vector2[/COLOR] position;[/FONT]

[FONT="] [COLOR=blue]public[/COLOR] [COLOR=#2B91AF]Vector2[/COLOR] Position { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] [COLOR=blue]this[/COLOR].position; } }[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]protected[/COLOR] [COLOR=blue]float[/COLOR] speed;[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]abstract[/COLOR] [COLOR=blue]void[/COLOR] Movement();[/FONT]



There’s a lot in here including some types you’ve never seen before so I’ll start by explaining these:


Texture2D – This type is used to store an image such as a png, jpg, bmp, tiff etc. When creating 2D games it is a very important class to understand. There are two ways to load a file in to an object of this type: using the FromFile method that loads an image from the local file system, or, using a ContentManager to load it from the Content folder of our project (this is the method we will be using).


Vector2 – This class is very similar (in fact, nearly identical) to the Point class. It stores a point within a 2D space. We will nearly always us this class to represent the position of a Texture2D object on the screen.


In the GameEntity class we have one object for each of these new types, plus a property each to allow external read access to them. We also have a float labelled ‘speed’ that we will discuss later. Additionally all of these members are protected so that classes that inherit GameEntity will be able to access the members directly. Last for this class, we have the declaration of an abstract method, Movement. This method (as you already know of course blah blah blah), will be used in all inheriting classes.


Now that our GameEntity class is finished we can move on to creating some new classes!

Ha, I Fooled You Again!


Ok, so we’re not going to make any objects yet, we’re going to do something entirely different, we’re going to learn how to handle input. Why? Because I feel like it, and also because making classes to inherit our GameEntity class is far to obvious :-)



Now, handling input is ridiculously easy thanks to the awesome Input library in the XNA Framework. The Input library allows the user to easily obtain input from the keyboard, mouse and Xbox 360 Gamepads, as well as providing various tools to play with the data it provides.


To handle our input we’re going to need another class so create a new one in the project and name the file InputManager.cs. This time we need to add a slightly different ‘using’ statement. Forget the ones we added to our other classes and instead add this one underneath the defaults:



[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] Microsoft.Xna.Framework.Input;[/FONT]

Next, add the abstract keyword before the class declaration. As with the GameEntity class, we won’t be creating any instances of the InputManager class, however, we won’t be inheriting it in other classes. Instead, we are going to make all the methods and members of the class static. There are two reasons for this: one, each member of the class is unique as we only need one of each member to exist in our program and, two, we need a number of objects to be able to access the members of this class easily and affordably.


Now we need to add some class members and properties. Add the following to the top of the class:



[FONT="] [COLOR=blue]private[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=#2B91AF]KeyboardState[/COLOR] ks;[/FONT]

[FONT="] [COLOR=blue]private[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=blue]bool[/COLOR] key_up, key_down, key_space;[/FONT]

[FONT="] [COLOR=green]//State properties (read only)[/COLOR][/FONT]

[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=blue]bool[/COLOR] KeyUp { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] key_up; } }[/FONT]

[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=blue]bool[/COLOR] KeyDown { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] key_down; } } [/FONT]

[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=blue]bool[/COLOR] KeySpace { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] key_space; } }[/FONT]



The only thing new in the code above is the type KeyboardState. As implied by the name, objects of this type store information on the state of the keyboard; namely whether keys are pressed or are being held. Other than that we have a number of Boolean variables that will store the state of individual keys when we check the state of the keyboard, and their respective properties that other objects will use to read them.


Next, we need to create a method for updating the state of each key. Insert the following code underneath the property declarations:



[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]static[/COLOR] [COLOR=blue]void[/COLOR] Update()[/FONT]

[FONT="] {[/FONT]

[FONT="] ks = [COLOR=#2B91AF]Keyboard[/COLOR].GetState();[/FONT]

[FONT="] [/FONT]

[FONT="] key_up = ks.IsKeyDown([COLOR=#2B91AF]Keys[/COLOR].Up);[/FONT]

[FONT="] key_down = ks.IsKeyDown([COLOR=#2B91AF]Keys[/COLOR].Down);[/FONT]

[FONT="] key_space = ks.IsKeyDown([COLOR=#2B91AF]Keys[/COLOR].Space);[/FONT]

[FONT="] }[/FONT]

This code is fairly simple to understand and demonstrates the ease with which the Input library can be used. In the first line, we retrieve the current state of the keyboard and store it in our KeyboardState object. In the three lines that follow, we read the state of each of the keys that we will be working with and store each of their states in their respective Booleans.


Last, we must make sure that the Input is updated each frame so that we can use it to manipulate the game, so, go back to the GameScreen class and enter the following a the top of the Update method:



[FONT="] [COLOR=#2B91AF]InputManager[/COLOR].Update();[/FONT]



Shazzam! We have input that is accessible by any object and that is guaranteed to be up-to-date when accessed. Now we’ll move on to finally making some objects!

I’m Serious This Time


Honestly, we really are going to make some objects. So go ahead and create yourself three new classes: GamePlayer.cs, GameComputer.cs and GameBall.cs. Next, change each class declaration so that they inherit from GameEntity – do this in exactly the same way that GameScreen inherited from DrawableGameComponent. Next give each class a constructor as follows (replace the name as necessary):



[FONT="] [COLOR=blue]public[/COLOR] GamePlayer([COLOR=#2B91AF]Texture2D[/COLOR] sprite, [COLOR=#2B91AF]Vector2[/COLOR] position)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].sprite = sprite;[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position = position;[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].speed = 4.0f;[/FONT]

[FONT="] }[/FONT]

The constructor for the GameBall class will look exactly the same, except, we need to change one thing: in the GameComputer constructor, change the assignment to ‘speed’ to 2.5f. The reason for this will become apparent later (in fact, you can probably hazard an accurate guess now).


Next, we need to make a few additional changes to the GameBall class. First, add the following members above the constructor:



[FONT="] [COLOR=#2B91AF]GamePlayer[/COLOR] player;[/FONT]

[FONT="] [COLOR=#2B91AF]GameComputer[/COLOR] computer;[/FONT]

[FONT="] [COLOR=#2B91AF]Rectangle[/COLOR] ballRect, playerRect, computerRect;[/FONT]

[FONT="] [COLOR=blue]bool[/COLOR] directionLeft, directionUp;[/FONT]



You’ll notice the first two members are objects of our two other new classes, GamePlayer and GameComputer. These are going to store references to the objects of these types we will be creating in our GameScreen class. Next we have a series of Rectangle, one for each of our GameEntity-inheriting objects: we will use this to store the position and dimension of each of these objects (you may be wondering why we need to store a reference to our objects AND have rectangles for them too. You’ll see shortly.) Finally, we have two Booleans representing directions along the X and Y axis (eg. DirectionLeft = false, indicates ‘right’).


Now we need to make some changes to the constructor to account for these. Modify the constructor so it appears as follows:



[FONT="] [COLOR=blue]public[/COLOR] GameBall([COLOR=#2B91AF]Texture2D[/COLOR] sprite, [COLOR=#2B91AF]Vector2[/COLOR] position,[/FONT]

[FONT="] [COLOR=#2B91AF]GameComputer[/COLOR] computer, [COLOR=#2B91AF]GamePlayer[/COLOR] player)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].sprite = sprite;[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position = position;[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].speed = 4.0f;[COLOR=green][/COLOR][/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]this[/COLOR].directionLeft = [COLOR=blue]true[/COLOR];[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].directionUp = [COLOR=blue]true[/COLOR];[COLOR=green][/COLOR][/FONT]

[COLOR=green][FONT="] [/FONT][/COLOR]

[FONT="] [COLOR=blue]this[/COLOR].player = player;[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].computer = computer;[/FONT]

[FONT="] }[/FONT]



As you can see our constructor now takes parameters for our other two classes and assigns them to their respective members. We also assign the ‘true’ value to both our direction; from this you can probably tell that the default directions for our ball are ‘up’ and ‘left’ (ie. This is the direction the ball will head in when the game starts).


Moving on, we also need to make a small but similar change to the GameComputer class. Above the constructor for this class, add the following member:



[FONT="] [COLOR=#2B91AF]GameBall[/COLOR] BALL_REF;[/FONT]



Now, you probably think we need to change the constructor so that it takes a GameBall object as a parameter and assigns it to BALL_REF in the body of the constructor. If you do, you’d be wrong. Here, we have a classic case of the chicken and the egg. Notice how our GameBall constructor requires our GameComputer and GamePlayer objects to be passed. This means that both of these objects need to be initialised before they are passed to the GameBall as passing uninitialized members will cause us a bucket of trouble. And herein lays the problem. If the GameComputer class takes a GameBall parameter, and the GameBall class takes a GameComputer parameter, we can’t pass one to the other without it being initialised and we can’t initialise it without passing it the other one. Thus, we are left in a pickle. Not to worry though, we’ll deal with it later :-)


Lastly for this section, we need to add the following to all three of our new classes:



[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]override[/COLOR] [COLOR=blue]void[/COLOR] Movement()[/FONT]

[FONT="] {[/FONT]

[FONT="] }[/FONT]




Here we have simply overridden the Movement method from our base class in our derived classes. But of course, you already know that ;-) Each of our objects will require movement and so they all need to override this method. Time to move back in to the GameScreen classes so we can start using our new objects.

Back To The Drawing Board


You probably saw this coming but anyhow... Reopen the GameScreen classes and add the following members to the two existing ones:



[FONT="] [COLOR=blue]private[/COLOR] [COLOR=#2B91AF]GamePlayer[/COLOR] player;[/FONT]

[FONT="] [COLOR=blue]private[/COLOR] [COLOR=#2B91AF]GameComputer[/COLOR] computer;[/FONT]

[FONT="] [COLOR=blue]private[/COLOR] [COLOR=#2B91AF]GameBall[/COLOR] ball;[/FONT]


Now we need to initialise them in the constructor. Add the following to the bottom of the constructor:



[FONT="] [COLOR=#2B91AF]Texture2D[/COLOR] paddleTexture = GAME_REF.Content.Load<[COLOR=#2B91AF]Texture2D[/COLOR]>([COLOR=#A31515]"paddle"[/COLOR]);[/FONT]

[FONT="] [COLOR=#2B91AF]Texture2D[/COLOR] ballTexture = GAME_REF.Content.Load<[COLOR=#2B91AF]Texture2D[/COLOR]>([COLOR=#A31515]"ball"[/COLOR]);[/FONT]

[FONT="] [/FONT]

[FONT="] player = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]GamePlayer[/COLOR]([/FONT]

[FONT="] paddleTexture,[/FONT]

[FONT="] [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Vector2[/COLOR]([/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])(container.X + 20),[/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])(container.Y + container.Height / 2 - paddleTexture.Height / 2)[/FONT]

[FONT="] )[/FONT]

[FONT="] );[/FONT]

[FONT="] computer = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]GameComputer[/COLOR]([/FONT]

[FONT="] paddleTexture,[/FONT]

[FONT="] [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Vector2[/COLOR]([/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])(container.X + container.Width - paddleTexture.Width - 20),[/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])(container.Y + container.Height / 2 - paddleTexture.Height / 2)[/FONT]

[FONT="] )[/FONT]

[FONT="] );[/FONT]

[FONT="] ball = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]GameBall[/COLOR]([/FONT]

[FONT="] ballTexture,[/FONT]

[FONT="] [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Vector2[/COLOR]([/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])(container.X + container.Width / 2 - ballTexture.Width / 2),[/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])(container.Y + container.Height / 2 - ballTexture.Height / 2)[/FONT]

[FONT="] ),[/FONT]

[FONT="] computer,[/FONT]

[FONT="] player[/FONT]

[FONT="] );[/FONT]



This is probably the largest chunk of code so far and contains some parts that you are almost definitely not familiar with. Let’s first deal with the first two lines. Here we have created two Texture2D objects and assigned to them using the ContentManager found in our Game1 object. Specifically we have used its Load method. The Load method works by specifying as a parameter the filename of the content we want to loan, but without the file extension. The Load method then returns the content specified in the form of the type specified in the angle brackets (in this case Texture2D – good old generics/templates at work). It’s seriously that simple!


Following these two lines we create our three objects. There’s not actually much going on here. We pass each object it’s relevant texture as specified in the top two lines, we create a Vector2 for each object to specify its position (the specifics of this don’t really matter – the Maths is fairly simple and even if you don’t understand it you’ll see the results shortly), and in the case of the ‘ball’ object, we pass references to our two other objects. Simple.


Now, before we see some results, we first need to go back to our Game1 class and change some things. First go into the class and find the Draw method and find a line referring to a method named Clear called from the GraphicsDevice object, then change it so it reads as follows:



[FONT="] GraphicsDevice.Clear([COLOR=#2B91AF]Color[/COLOR].Black);[/FONT]



Here we’ve simply change the single parameter to Color.Black because in Pong the screen is black (duh!). NOTE: In the source code this line is in the GameScreen class for demonstrative purposes.


Next, we need to get access to the private SpriteBatch object so add the following to the members above the constructor:



[FONT="] [COLOR=blue]public[/COLOR] [COLOR=#2B91AF]SpriteBatch[/COLOR] sb { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] [COLOR=blue]this[/COLOR].spriteBatch; } }[/FONT]



Now go back to the GameScreen class and add the following to the body of the draw method:



[FONT="] GAME_REF.sb.Begin([COLOR=#2B91AF]SpriteBlendMode[/COLOR].AlphaBlend);[/FONT]

[FONT="] [/FONT]

[FONT="] GAME_REF.sb.Draw(player.Sprite, player.Position, [COLOR=#2B91AF]Color[/COLOR].White);[/FONT]

[FONT="] GAME_REF.sb.Draw(computer.Sprite, computer.Position, [COLOR=#2B91AF]Color[/COLOR].White);[/FONT]

[FONT="] GAME_REF.sb.Draw(ball.Sprite, ball.Position, [COLOR=#2B91AF]Color[/COLOR].White);[/FONT]

[FONT="] [/FONT]

[FONT="] GAME_REF.sb.End();[/FONT]



You’re probably wondering what’s going on here. Or maybe you’re not. Either way, I’d better explain. The SpriteBatch is a bit like a machine – a car, say – and so before we can use it we need to switch on the engine: this is the function of the ‘begin’ method. Next we use the SpiteBatch as intended, to draw our content to the screen, so we have one line for each of our objects. For each, we pass the SpriteBatch three parameters: the sprite we want to draw, the position we want to draw it at, and the colour we want to make it (in this case we don’t want any colour, thus we use white which makes the image appear as is). Last, we turn the engine off using the ‘End’ method. You may notice that the ‘begin’ method takes a parameter to; there a number of SpriteBlendModes but you need not worry about them unless you’re messing round with advanced graphics (like particle effects etc.) Also, there are a number of overloads for the Draw method so feel free to mess around with them to your hearts content (provided you change them back once you’re finished) as you can do all manner of things such as scaling, rotating and centring your sprites . Finally, we can now see some results.


We Made Stuff Happen!


It’s time to check that our program works. First add this line to the Initialize method of the Game1 class:



[FONT="] Components.Add([COLOR=blue]new[/COLOR] [COLOR=#2B91AF]GameScreen[/COLOR]([COLOR=blue]this[/COLOR]));[/FONT]



This line simply makes our GameScreen run alongside our Game1 object in sync with the game. In our case the GameScreen class IS our game so we of course need to add it to the Components list.


Now, finally, we can test our game! I’m biting a knuckle right now because heaven knows that when the debug button get’s clicked half of you are going to see two paddles and a ball on a black screen (I’m going to call you Group A) and half of you are going to get a box saying that the project failed to compile, followed by a ton of errors. Oh well, here goes. Either, press the Debug button (looks like a green arrow) under the menu bar, or hit the F5 key to start debugging.


Group A: Congratulations, you have drawn some basic images to the screen and we are most of the way towards creating our game! Well done, and keep up the good work!


Group B: Pay attention you arsehole! You’ve CLEARLY made some spelling mistakes or followed my instructions incorrectly you cretin! Just kidding ;-) Seriously though, read through the errors and try to deal with them in a methodical manner. If that doesn’t work, try comparing your code to that given in the finished project provided at the bottom of this tutorial. If that doesn’t work either, delete your project and start the tutorial from scratch. I suppose if you really don’t want to do that you can PM me with your error(s) but if there’s lots of them and it looks like you’ve either a) made obvious spelling/grammar mistakes or b) have followed my instructions incorrectly, I’m liable to just get annoyed at you and not message you back so be VERY sure that you have a genuine problem before PMing me.


Provided you’re in Group A, the hard part’s over now it’s time to move on to the fun bit!


Yeah That’s Right, I Lied Again


Haha! The hard part is so not over! I can’t believe you fell for that! I know I’m evil but nothing comes easy and you should know that by now :-) It’s time to add some movement logic to our classes. Sadly, each class needs its own unique Movement method and so we can’t create reusable code for all the classes. We’ll start with the GamePlayer class. Add the following in the body of the Movement method:



[FONT="] [COLOR=blue]if[/COLOR] ([COLOR=#2B91AF]InputManager[/COLOR].KeyUp && [COLOR=#2B91AF]InputManager[/COLOR].KeyDown)[/FONT]

[FONT="] [COLOR=blue]return[/COLOR];[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (position.Y >= 20)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]if[/COLOR] ([COLOR=#2B91AF]InputManager[/COLOR].KeyUp)[/FONT]

[FONT="] {[/FONT]

[FONT="] position.Y -= speed;[/FONT]

[FONT="] [COLOR=blue]return[/COLOR];[/FONT]

[FONT="] }[/FONT]

[FONT="] }[/FONT]

[COLOR=green][FONT="] [/FONT][/COLOR]

[FONT="] [COLOR=blue]if[/COLOR] (position.Y <= [COLOR=#2B91AF]GameScreen[/COLOR].Container.Y + [COLOR=#2B91AF]GameScreen[/COLOR].Container.Height - sprite.Height - 20)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]if[/COLOR] ([COLOR=#2B91AF]InputManager[/COLOR].KeyDown)[/FONT]

[FONT="] {[/FONT]

[FONT="] position.Y += speed;[/FONT]

[FONT="] [COLOR=blue]return[/COLOR];[/FONT]

[FONT="] }[/FONT]

[FONT="] }[/FONT]



So, we’ve got three ‘if’ statements, lets go through them. The first ‘if’ statement is fairly simple: if both the up and down buttons are pressed, don’t run the rest of the method. Why? Because if both buttons are pressed, we don’t want one to take precedence over another as it’s annoying for the player. Our second ‘if’ statement says that if the paddle isn’t more than twenty pixels from the top of the screen and the up button is pressed, move the paddle upwards, and our third ‘if’ statement says the exact opposite (ie. twenty pixels from the bottom and down button).


Now, before we move on we should make a quick addition to the GameScreen class so that I don’t forget later. Add this to the GameScreen class’s Update method:



[FONT="] player.Movement();[/FONT]

[FONT="] computer.Movement();[/FONT]

[FONT="] ball.Movement();[/FONT]

Good, now we can continue. Next we’ll work on the GameBall class’s Movement method. Add the following in to it:



[FONT="] [COLOR=blue]if[/COLOR] (directionLeft)[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position.X -= speed;[/FONT]

[FONT="] [COLOR=blue]else[/COLOR][/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position.X += speed;[/FONT]

[COLOR=green][FONT="] [/FONT][/COLOR]

[FONT="] [COLOR=blue]if[/COLOR] (directionUp)[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position.Y -= speed;[/FONT]

[FONT="] [COLOR=blue]else[/COLOR][/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position.Y += speed;[/FONT]



This code is fairly simple to understand, it just sends the ball in the stated direction(s) at the required speed. However, the rest of the GameBall class is not so simple. With the way the class is set currently, when we start the game, the ball will head in the correct direction, go straight off the screen, and off into the great yonder. To deal with this we need to add two new methods, so insert the following in to the GameBall class below the Movement method:



[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]void[/COLOR] Collision()[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (position.Y <= [COLOR=#2B91AF]GameScreen[/COLOR].Container.Y)[/FONT]

[FONT="] directionUp = [COLOR=blue]false[/COLOR];[/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (position.Y >= [COLOR=#2B91AF]GameScreen[/COLOR].Container.Y + [COLOR=#2B91AF]GameScreen[/COLOR].Container.Height - sprite.Height)[/FONT]

[FONT="] directionUp = [COLOR=blue]true[/COLOR];[/FONT]

[COLOR=green][FONT="] [/FONT][/COLOR]

[FONT="] playerRect = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR](([COLOR=blue]int[/COLOR])player.Position.X, ([COLOR=blue]int[/COLOR])player.Position.Y, player.Sprite.Width, player.Sprite.Height);[/FONT]

[FONT="] computerRect = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR](([COLOR=blue]int[/COLOR])computer.Position.X, ([COLOR=blue]int[/COLOR])computer.Position.Y, computer.Sprite.Width, computer.Sprite.Height);[/FONT]

[FONT="] ballRect = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR](([COLOR=blue]int[/COLOR])[COLOR=blue]this[/COLOR].position.X, ([COLOR=blue]int[/COLOR])[COLOR=blue]this[/COLOR].position.Y, [COLOR=blue]this[/COLOR].sprite.Width, [COLOR=blue]this[/COLOR].sprite.Height);[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (ballRect.Intersects(playerRect))[/FONT]

[FONT="] directionLeft = [COLOR=blue]false[/COLOR];[/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (ballRect.Intersects(computerRect))[/FONT]

[FONT="] directionLeft = [COLOR=blue]true[/COLOR];[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (position.X - sprite.Width <= [COLOR=#2B91AF]GameScreen[/COLOR].Container.X[/FONT]

[FONT="] || position.X >= [COLOR=#2B91AF]GameScreen[/COLOR].Container.X + [COLOR=#2B91AF]GameScreen[/COLOR].Container.Width)[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].Reset();[/FONT]

[FONT="] }[/FONT]

[FONT="] [/FONT]

[FONT="] [COLOR=blue]private[/COLOR] [COLOR=blue]void[/COLOR] Reset()[/FONT]

[FONT="] {[/FONT]

[FONT="] position = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Vector2[/COLOR]([/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])([COLOR=#2B91AF]GameScreen[/COLOR].Container.X + [COLOR=#2B91AF]GameScreen[/COLOR].Container.Width / 2 - sprite.Width / 2),[/FONT]

[FONT="] ([COLOR=blue]float[/COLOR])([COLOR=#2B91AF]GameScreen[/COLOR].Container.Y + [COLOR=#2B91AF]GameScreen[/COLOR].Container.Height / 2 - sprite.Height / 2)[/FONT]

[FONT="] );[/FONT]

[FONT="] [/FONT]

[FONT="] directionLeft = !directionLeft;[/FONT]

[FONT="] directionUp = !directionUp;[/FONT]

[FONT="] }[/FONT]



Ok, so, we’ve got a lot of stuff here. Let’s look at the Reset method first. This method moves the ball back to the centre of the screen and changes the direction to the opposite of what they are currently. Simple enough.


Then there’s the collision method. This is a little more complex. The first two ‘if’ statements check whether the ball has hit the top or bottom of the screen and, if it has, “bounces” the ball back in the opposite direction on the Y-axis. Next, we update the rectangles for the positions of our objects, and then, in the two ‘if’ statements that follow them, check whether the GameBall rectangle intersects either paddle, and if it does, “bounce” it off the given paddle. Finally, we check whether the ball has left the screen along the X-axis (ie. gone behind either paddle) and if it has, reset its position.


Done! Now we can move our players paddle, and our ball will bounce around the screen as it should. We are almost at the end of the code-writing part of this tutorial. We have one last method to write: the Movement method of the GameComputer class. Insert the following into the body of the method:



[FONT="] [COLOR=blue]if[/COLOR] (BALL_REF.Position.X > [COLOR=#2B91AF]GameScreen[/COLOR].Container.X + [COLOR=#2B91AF]GameScreen[/COLOR].Container.Width / 2)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]if[/COLOR] (BALL_REF.Position.Y + BALL_REF.Sprite.Height / 2 > [COLOR=blue]this[/COLOR].position.Y + [COLOR=blue]this[/COLOR].sprite.Height / 2)[/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position.Y += speed;[/FONT]

[FONT="] }[/FONT]

[FONT="] [COLOR=blue]else[/COLOR][/FONT]

[FONT="] {[/FONT]

[FONT="] [COLOR=blue]this[/COLOR].position.Y -= speed;[/FONT]

[FONT="] }[/FONT]

[FONT="] }[/FONT]



Congratulations our computer player’s artificial intelligence is complete and, yes, it actually is that easy. It’s so easy I don’t think I even need to explain what’s going on in the method. Well, OK, I’ll explain but still, it’s seriously simple. The logic goes as follows: If the ball is in the Computers half of the screen, then move the paddle upwards if the ball is above it and downwards if the ball is below it.


Next, we need to do a few small changes and additions to round things up. First add this method to the bottom of the GameComputer class:



[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]void[/COLOR] PassBallRef([COLOR=#2B91AF]GameBall[/COLOR] b)[/FONT]

[FONT="] {[/FONT]

[FONT="] BALL_REF = b;[/FONT]

[FONT="] }[/FONT]



Now, add the following to the end of the GameScreen constructor:



[FONT="] computer.PassBallRef(ball);[/FONT]

Then add the following to the end of the GameScreen class’s Update method:

[FONT="] ball.Collision();[/FONT]

And that’s all there is for this tutorial. Our coding is done, so do what you know you want to and hit the Debug button, play your Pong-clone, and enjoy your creation!


You’ve Learned Your Lesson


In all honesty, I imagine most of you haven’t learned much. After all, if you already had a moderately strong grasp of the C# language then all you might have learned is a few new types, some game design basics, and a little syntactic sugar. A few may have learned nothing at all, and maybe even abhor some of my coding practices. Still, assuming you’re new to XNA, you all now have the skill to do these things:

  • Load content using the built-in content management system.
  • Draw 2D images to the screen.
  • Take input from the keyboard.
  • Move images around the screen.
  • How to perform basic collision detection.
  • How to implement basic artificial intelligence.


And believe me, these may only be the basics but they can be used to build a million different games. Sure, there are still some things you could do with knowing: how to deal with sound, how to implement a scoring system, how to add a main menu, and so on. Don’t you worry though; we’ll deal with these in the next tutorial :-)


For now, enjoy playing you Pong-clone, mess around with the code, change the speeds of the objects and how they are drawn to the screen, and generally just play around!


Until the next tutorial, goodbye!


The Legal Bit: This tutorial is not for sale. Use it however you want but 1. credit me, and 2. give it away for free. If forced to pick a licence, I suppose I would pick the GPL which can be found here

Edited by Roger, 28 January 2011 - 09:59 PM.


#2
James.H

James.H

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 866 posts
Very interesting and well layed out, perfect for a anyone new to XNA.

Thanks semprance. +rep!

#3
James.H

James.H

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 866 posts
Also looking forward to part 2 :)

#4
gokuajmes

gokuajmes

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 518 posts
so that was awesome , neat language and interactive explanation. Go ahead dude ,^^.I know all that's needed for game programming except the XNA framework , I wish i could learn some game development.

#5
semprance

semprance

    Programmer

  • Members
  • PipPipPipPip
  • 126 posts
Glad people are enjoying it! Part 2 is on the way :-)

#6
Arpimohit

Arpimohit

    Newbie

  • Members
  • Pip
  • 1 posts
Hey,

There's an error in the above code:


public static void Update()
{
ks = Keyboard.GetState();
key_up = (ks.IsKeyDown(Keys.Up)); //And not key_up = (ks.IsKeyUp(Keys.Up))
key_down = (ks.IsKeyDown(Keys.Down));
key_space = ks.IsKeyDown(Keys.Space);
}
The game play became different because of that small error..

and bdw, excellent tutorial. It helped us a lot