Developing Programming Assignments on the XBOX 360 Console

 

Section II: The XnaAssignmentBase Library

a. The library SDK

 

Back to workshop main page


This is a wrapper class over the XNA framework. This class is designed to be simple and easy to use. As such, only drawings of circles and rectangles in 2D space are supported. Except for input from the Gamepad, programmers working with the XnaAssignmentBase class do not need to know anything about the XNA framework. If you are interested (and only if you are interested) here is the source code to the XnaAssignmentBase library. Note that you do not need to look at the source code implementation to learn how to work with the library. You should be able to read through this entire tutorial without looking at the source code of the XnaAssignmentBase library.

 

This document uses a simple working program (download the TemplateAssignment.zip) to explain how to work with the XnaAssignmentBase class.

 

The Sample Template Application:

Unzip TemplateAssignment.zip and you will see a folder named TemplateAssignment, inside this folder are two items:

  1. Assignment_PC.sln: this is the XNA Game Studio (XNA GS) solution file.

 

  1. Assignment: this is a folder including the following files and subfolders:

 

Folders/Files

Purposes

Assignment_PC.csproj

XNA GS project description file. This file is necessary but we will not work with this file.

Assignment.cs

This is the one file that contains the interesting source code of our project. This document will only refer to source code from this file.

Program.cs

A dummy container. We do not need to be concerned with the contents of this file.

Game.ico

GameThumbnail.png

Image on the top-left corner of the title bar of the application window and when the application window is iconized.

SupportFiles/XnaAssignmentBase_PC.dll

The DLL library file that contains the XnaAssignmentBase.

Properties/AssemblyInfo.cs

Contains miscellaneous information on the application. We will not work with this file. 

Content/Content.contentproj

XNA GS content project description file. This file is necessary but we will not work with this file.

Content/Resources/Fonts/Arial.spritefont

 The font used by our application. This folder and the font that must exist for all XnaAssignmentBase projects!

Content/Resources/Textures/bgTexture.jpg

Content/Resoruces/Textures/uwb_logo.jpg

Images that are used as textures in our drawings. We will discuss the use of these images when discussing drawing of circles and rectangles.

Content/Resoruces/Audio/GameAudio.xap

This is a project file created by the Microsoft Cross-Platform Audio Creation Tool. We will discuss this file in details at the very last of this tutorial guide.

Table 1: Folders and Files of the sample template project

 

Now, start the XNA GS, build and run the program. Figure 1 shows what you will see when running this application.

 


 

You should observe an application window with light pink background color; four circles one at each corner of the window; a small rectangle in the center; and two rather large rectangles connecting top and bottom right to the center. To interact with this example:

 

Left/Right Triggers: press and hold the left or right trigger on the controller, the center rectangle and bottom right circle will rotate and the controller will vibrate (no vibration effects on the keyboard).

 

The rest of this document explains, in detailed, how to accomplish all these functionality.

 

To work with the XnaAssignmentBase class to implement the sample template application, we only need to pay attention to Assignment.cs file. Please refer to Assignment.cs file for the following discussion.

 

There are 6 important aspects to using the XnaAssignmentBase class:

 


1. Declaring and Using Library

The very first few lines of source code in Assignment.cs file are the C# using statements:

using System;                           // System libraries

using System.Text;                      // Text

using System.Collections.Generic;       // Collections

 

using Microsoft.Xna.Framework;          // XNA libraries

using Microsoft.Xna.Framework.Graphics; // Utilities (e.g.,Vector2)

using Microsoft.Xna.Framework.Input;    // For GamePad object

 

using XnaAssignments;                  // Our own library

 

Notice that besides using typical system libraries, we must also use the XNA libraries. The XnaAssignments is referring to the XnaAssignmentBase library.


 

To ensure proper linking, the XnaAssignmentBase must be properly referenced from the References folder. As shown in Table 1, the library file, XnaAssignmentBase_PC.dll, is located in the SupportFiles folder of the project.

 


2. Resources Folders (Fonts, and Texture Images)

The XnaAssignmentBase library assumes that the Resources folders to be part of the uapplication project. The following figure shows the Resources folders.


 

Notice that the Audio, Fonts and Textures subfolders must be present:

  1. Content/Resources/Audio/GameAudio.xap

This is a project file created by the Microsoft Cross-Platform Audio Creation Tool. This tool is part of the XNA Game Studio distribution. You should be able to double click this file and start the audio creation tool. If this file is missing, your application will still run. However, without this file your application cannot generate any audio effects. We will discuss audio support at the very last of this tutorial.

 

  1. Content/Resources/Fonts/Arial.spritefont

This is the font used by the library in displaying status to the application window. This Font must be present in this folder, otherwise, the application will fail!

 

  1. Content/Resources/Textures/images

These are jpg images referenced by our drawing routines. Notice that these images are in jpg format. Any images referenced by drawing must be stored into this folder, otherwise, the application will fail.

 


3. Subclass from XnaAssignmentBase

The main class for the application (in this case the Assignment class) must be a sub-class of the XnaAssignmentBase class. The following code shows the declaration of the Assignment class.

 

public class Assignment : XnaAssignmentBase {

   private const float WORLD_MIN_X = 5.0f;  // min corner is (5, 10)

   private const float WORLD_MIN_Y = 10.0f;

   private const float WORLD_WIDTH = 20.0f; // width is 20.0

          

   // Notice we must call the base constructor!

   public Assignment() :

          base(new Vector2(WORLD_MIN_X, WORLD_MIN_Y), WORLD_WIDTH)

   {

          // Notice: memory allocation and initialization should be performed

          //         in InitializedWorld(). The constructor should be empty.

   }

 

Notice that we must call the base class constructor when constructing the Assignment class. In this case, we are defining a drawing area where the bottom-left corner is defined to be (5,10) with the width of the drawing area being 20.  Since the graphics device is created and initialized after the constructor, to avoid potential bugs, it is recommended that all memory allocation and initialization be performed in the InitializedWorld() function. The constructor should be left empty.

 

A note about drawing dimension:

When calling the base class constructor, we as the programmer, we can define the coordinate range for drawing in the application window. Noice that this range is independent from the hardware pixel units. In this case, for illustration purposes, we have chosen the lower left corner to be cooridnate position . This is to say, if we draw a circle with radius of 1 at position (6,11), the circle will show up at the lower left corner with left and bottom of the circle touching the left and bottom edges of the application window. The light gray circle at the lower left corner of Figure 1 is such a circle. We will examine the details of drawing this circle later.

 

Due to the aspect ratio limitation of HDTV, the height and width of the drawing area are always related with a fixed aspect ratio:


In this case, with a width of 20, the height of the drawing area is:


This means, the center of the drawing area is:


As highlighted at the bottom of Figure 1 and as will be discussed later, when running the sample template application, the computed center position is indeed (15, 15.625). We will examine the computation of these values later.

 


4. Override functions

As a programmer using the XnaAssignmentBase class, we must override three functions:

protected override void InitializeWorld() {

   // BackgroundTexture = @"bgTexture"; // texture image name              

   BackgroundColor = Color.LightPink;

}

protected override void UpdateWorld() {

   // Input values from the Gamepad

     // Details shown in the last section.

   m_Rotation += rotR - rotL;

   if (rotR > 0)

       XnaAssignmentBase.PlayACue(1.0f, "Right"); // right audio effect

  

}

protected override void DrawWorld() {

   // Draws all the circles and rectangles

     // Details shown in next section.

}

 

  1. InitializeWorld()

This function is called exactly once at the beginning of the application. We should allocate memory and initialize variables in this routine. In the above case, we initialize the background color to be light pink. The commented out code sets the background to be an textured image. You are encouraged to un-comment the line and re-compile/re-run the application to observe the differences. We will discuss about BackgroundColor and BackgroundTexture later.

 

NOTE: The commented out line assigns bgTexture to be the background texture image. Notice that “beTexture” is the name of the “bgTexture.jpg” file located in the Content/Resources/Textures folder. Notice that the image file must exist in the texture folder. In addition, notice that the image file is referred to without the “.jpg” extension.

 

  1. UpdateWorld()

This function is called once about every 25 milliseconds. Notice that this is frequent enough for real time animations. As an application programmer, we should udpate the values of the instance variables according to the logics of our application. In this case, rotR and rotL are values from the gamepad triggers: when the user press the gamepad triggers, rotR and rotL will become non-zero. We increase/decrease the m_Rotation value accordingly. The m_Rotation value will be used in DrawWorld() to rotate the center rectangle and bottom right circle.  The PlayACue() function plays a short snipet of audio effect. In this case, a pre-recorded wave file that contains a cue namde “right” is played. We will discuss audio effect at the very last of this tutorial.

 

NOTE: It is very important to never issue any drawing commands from the UpdateWorld() function. DrawWorld() should be the only function that issues drawing commands.

 

  1. DrawWorld()

This function is also called once about every 25  milliseconds. This function complements the UpdateWorld() function, where after the application state is updated, this function will be responsible for drawing everything. The details of drawing is left until next section.

 

NOTE: It is very important to never change any application state (i.e., instance variables) in this function. UpdateWorld() is the function that is responsible for updating the instance variables. This function should only issue drawing commands.

 


5. Drawing and State Accessing Functions

 

The XnaAssignmentBase class supports a total of 3 2D drawing routines, and two different status echo functions. In addition, an application program can inquire about the drawing dimension and set the background color/texture. No other functions are supported. The simplicity and restriction are results of concious design decisions. We want to keep the library simple such that people with no gaming or graphics background can begin programming with minimal overhead.

 

Set background color/texture:

As we have already seen (in InitializeWorld()):

Color BackgroundColor – A write-only variable for setting the background of the drawing area (application window).

String BackgroundTexture – A write-only variable for setting an image to be the background of the drawing area (application window).

Notice that when BackgroundTexture is pointing to a valid image, the image will be displayed in the application window and BackgroundColor is ignored.

 

Inquire Drawing Dimension:

At any point in our application, when we need to find out about the dimension of the drawing area, we can access:

Vector2 WorldMin – A read-only variable that returns the coordinate position at lower left corner.

Vector2 WorldMax – A read-only variable that returns the cooridnate position at the upper right corner.

Notice that these variables are read-only. This means, once the cooridnate range is defined (during the base contructor call),  it cannot be changed during run-time.

 

Output Status Functions:

Please refer to Figure 1, the top and bottom left of the application window include text displays of the application status.

void EchoToTopStatus(String msg)

void EchoToBottomStatus(string msg)

 

 

Each of the above two functions is capable of echoing status to the corresponding area of the application window.

 

Draw Circle/Rectangle Functions:

The DrawCircle() function draws a circle based on a center and radius:


 

The first DrawRectangle() function draws a rectangle based on the center and dimension of the rectangle:


 

The second DrawRectangle() function draws a rectangle based on end positions and length of the rectangle:


 

In all three draw functions, texName can refer to a image texture file, or a null pointer. When present, the image will be pasted over the circle or rectangle.

 

DrwaWorld() function re-visit:

With the above discussion, we can now examine the details of the DrawWorld() function. The followings are the content of the DrawWorld() function:

// Label A:

float radius = 1.0f;

// set width and length to some constant values

 

// Label B:

Vector2 bottomLeft = new Vector2(WorldMin.X + 1, WorldMin.Y + 1);

Vector2 topLeft = new Vector2(WorldMin.X + 1, WorldMax.Y - 1);

Vector2 topRight = new Vector2(WorldMax.X - 1, WorldMax.Y - 1);

Vector2 bottomRight = new Vector2(WorldMax.X - 1, WorldMin.Y + 1);

Vector2 center = new Vector2(WorldMin.X + (WorldMax.X - WorldMin.X) / 2,

                             WorldMin.Y + (WorldMax.Y - WorldMin.Y) / 2);

 

// Label C: draws rectangle with two end points (white center)

DrawRectangle(bottomRight, center, radius, Color.Red, Color.White, null);

 

// Label D: draws the four corner circles

DrawCircle(bottomLeft, …, Color.LightGray, Color.LightGray, null);

DrawCircle(topLeft, …, Color.LightGray, Color.White, null);

DrawCircle(topRight, …, Color.LightGray, Color.Red, null);

DrawCircle(bottomRight, …, Color.LightGray, Color.Blue, @"uwb_logo");

 

// Label E: draws the center rectangle with image texture

DrawRectangle(center, length, width, …, @"uwb_logo");

 

// Label F: draws rectangle with two end points (Cyan)

DrawRectangle(topRight, center, radius, Color.Cyan, Color.Cyan, null);

 

// Label G: echo the status

EchoToTopStatus(@"…:" + topRight);

EchoToBottomStatus(@"…:" + bottomLeft + "   Center:" + center);

 

We see that:

·       Label A: variables are initialized. In particular, the radius variable for all the circles is set to 1.0.

·       Label B: bottomLeft, topLeft, topRight, and bottomRight are four corners each one unit away from the boundaries of the drawing area.

·       Label C: draws a rectangle with two end points. Notice the color settings, this is drawing the long rectangle on the right side of Figure 1, where the center of the rectangle is in white.

·       Label D: draws the four circles, each with radius of 1 and with center being distance of 1.0 away from the boundaries of the drawing area. Notice the four circles in Figure 1, each touching the boundaries of the drawing area. The important lesson to be learned here is that, we as programmer, we can define the drawing coordinate (when calling the base constructor) and we do not need to be concerned with the underlying pixel units.

·       Label E: draws a rectangle with a center and dimension. Notice we specify the “uwb_logo” as texture image for the rectangle. Once again, please refer to our earlier discussion, “uwb_logo” refers to the “uwb_logo.jpg” file, and this file must be located in the Resources/Textures folder.

·       Label F: draws a rectangle with both inside and boundary colors set to cyan. This will draw a solid cyan-color rectangle.

·       Label G: echo interesting coordinate information to the top and bottom echo areas. Notice that the center position is printed out to the bottom status area. Recall the discussion regarding coordinate definition; we can now verify these values.

 

Drawing Order:

Lastly, observe the drawing order of the rectangles. The Cyan rectangle is on top of (covers) the center rectangle, which is on top of the first drawn rectangle with white center. This observation tells us that later drawn objects override the color of the earlier drawn objects. If you want an object to be on top of all other objects, draw it the last.

 


6. Input Functions

For simplicity, the XnaAssignmentBase class simply duplicates and presents the GamePadState. Please refer to the xna.Framework.Input library, our input class works in exact the same way as the Gamepad (controller) device. At anywhere in our application, we can access the gamepad by:

XnaAssignmentBase.GamePad. …

 

 

Where

GamePad: works identical to xna.Framework.Input.GamePadState.

 

The following code segment is from UpdateWorld():

// Label A:

float rotL = XnaAssignmentBase.GamePad.Triggers.Left;

float rotR = XnaAssignmentBase.GamePad.Triggers.Right;

 

// Label B:

XnaAssignmentBase.SetGamePadVibration(PlayerIndex.One, rotL, rotR);

 

m_Rotation += rotR - rotL;

 

// Label C:          

if (XnaAssignmentBase.GamePad.ButtonBackClicked())

    this.Exit();

 

We see that:

·       Label A: set rotL, and rotR variables using the left and right triggers of the controller.

·       Label B: use the rotL and rotR values to vibrate the controller. When the triggers are not pressed, these variables will be zero, and the controller will not vibrate.

·       Label C: detect if the Back button has been clicked, if so quits the application.

 

NOTE: A Word about ButtonClick vs. ButtonState :

The GamePad structure reflects the state of the controller device. For example, it is possible to inquire if a button is pressed, e.g.:

If XnaAssignmentBase.GamePad.Buttons.A == ButtonState.Pressed)

Notice that a button pressed state is different from a button click action. The button state faithfully records the current condition of the button (released or pressed), while the click action records the button transition from released state to pressed state. XnaAssignmentBase library records button click actions for the following buttons:

A Button clicked: GamePad.ButtonAClicked()

B Button clicked: GamePad.ButtonBClicked()

X Button clicked: GamePad.ButtonXClicked()

Y Button clicked: GamePad.ButtonYClicked()

Start Button clicked: GamePad.ButtonStartClicked()

Back Button clicked: GamePad.ButtonBackClicked()

 

The following diagram illustrate the names of the input devices on the controller:

 


 

For more detailed information on the gamepad, please refer to:http://msdn2.microsoft.com/en-us/library/microsoft.xna.framework.input.aspx

 

In the absence of a dedicate XBOX 360 controller, the keyboard is automatically polled. Here is the supported keyboard mapping.

Limitations

1.     Single controller support: Currently this library only supports one game pad. At this point, there is no way to program with other game pads connected to the XBOX 360 unit. On a PC with keyboard, one can creatively map the left/right thumb sticks of the single game pad for two players.

 

2.     Vibration: Notice that the game pad vibration (SetGamePadVibration()) is set by a function and not through the GamePad object interface like the rest of input functionality. We will try to fix this problem in the future releases.

 


7. Audio Support

The only supported audio effect function is:

 

void XnaAssignmentBase.PlayACue(float length, String cueName)

 

Where

length: is how long (in seconds) to play the cue. For example, length of 0.8f will play the cue for 0.8 seconds.

cueName: is the name of the cue to be played.

Recall that:

 

Content/Resources/Audio/GameAudio.xap

 

is the file that contains the audio effects. If you double on this file, you will see:

1.     Wave Bank: XnaAssignmentBase assumes only one wave bank by the name of GameWaves. Notice that if GameWaves is missing, it will be a run time error and your application will crash. GameWaves should contain all the sound waves (in .wav format) you wish to use in your application. In this case, we use the SoundRecorder program and recorded us saying “Left” and “Right”. Store the two short snippets as “Left.wav” and “Right.wav” files. These two files are then loaded into the GamesWave wave bank. Warning: As illustrated in the following figure, with GameWaves selected, you should double to check under Windows Properties and Xbox 360 Properties and make sure the BuildNames are set to GameWaves.xbs (you can simply click-in and rename the fields).

 

 

2.     Sound Banks. XnaAssignmentBase assumes only one sund bank by the name of GameSounds. Notice that if GameSounds is missing, it will be a run time error and your application will crash. GameSounds should contain all the sounds you will to use in your program. In this case, we created the sounds from the corresponding wave files in the wave bank (by simply dragging the files from GameWaves over to GameSounds).  Warning: As illustrated in the following figure, similar to the GameWave’s case, with GameSoundss selected, you should double to check under Windows Properties and Xbox 360 Properties and make sure the BuildNames are set to GameSounds.xsb (you can simply click-in and rename the fields).

 

3.     Cues: in the XnaAssignmentBase.PlayACue(float length, String cueName) function, the cueName is referring to names of these cues. In our case, we simple drag the corresponding sounds from GameSounds into the Cue window to create the  “Left” and “Right” cues.

 

Notice that unlike the texture image files, where each texture image is presented as a separate file to our project. In the case of audio effects, our project only work with one single file: GameAudio.xap. For audio effects to operate properly, this file must be present in the Audio subfolder under Resources. All your wave files and cue snippets should be maintained by the GameAudio.xap file. Plesae refer to the following reference to find out more about how to work with the Microsoft Cross-Platform Audio Creation Tool. You may wish to consider copying the GameAudio.xap file from this project to your own project. You can then edit the file, remove/replace the wave files, and create appropriate sounds and cues from your own wave files.

 

Limitations

1.     Single bank support: Notice the extremely simple single bank audio effect support. This means, you cannot play more than one audio effects at a time! For example, the XnaAssignmentBase library does not support a background music going while overlaying foreground effects.

 

2.     Dropping of Cues: If you made multiple PlayACue() function calls in a short interval, chances are some of the cues will simply be dropped! Only one cue is played at anytime, during this time, the rests of the cues wait.  As time elapsed, all cues’ requested play time are updated (even for the waiting ones). When a cue’s requested play time expired, it is removed. For example, during UpdateWorld()  you issue two PlayACue() function calls, both with requests of one second. In this case, only one of the two cues will play (the first issued), while both cues will expired at the end of one second elapsed time. The second issued cue effect will simply be dropped.

 

HINTS on using Audio Cues: Our simple audio architecture support means we have very limited audio resources to play with. We should use this resource carefully and strategically to maximize support for and feedback to student.

1.     Use it as a hint to events: Use audio cues to inform students something has happened (e.g., the net has touched an insect), and do not attempt to use audio effect as any kind of background on-going music.

 

2.     Use one cue at a time: Since only one cue can be played at anytime, it is really useless to issue more than one cue effects at a time, i.e., do not call PlayACue() more than once during a single UpdateWorld() function.  For example, in your application a hero is walking and encountered gold nugget during a single UpdateWorld() function. It may be your desired to play a cue representing hero walking, and a separate cue representing the encountering of gold nugget.  In this case, you should weigh the importance and only play one of the cues.

 

3.     Use shorter cues rather than longer cues: The audio support will honor the requested duration of a cue before continuing to the next cue. This means, if you start a 5 minute audio effect, within this 5 minutes no other audio effects will be played. In general multiple meaningless short audio snippets corresponding to significant events is much more informative than one meaningful audio segment representing one of the significant events. For example, if 5 collisions occurred over a period of 1 seconds. In this case it is much more informative for the user to hear 5 distinct audio cues (each can be 0.1 seconds in length), than for the user to hear a single one-second audio segment that accurately represents one of the 5 collisions. With our simple library support, in general, your audio cues should probably be less than 1 seconds.


REFERENCES

 

Color: defined in System.Drawing. Please refer to http://msdn2.microsoft.com/en-us/library/system.drawing.color.aspx for more information.

 

String: defined in Sytem.String. Please refer to http://msdn2.microsoft.com/en-us/library/system.string.aspx for more information.

 

Vector2: defined in Microsoft.xna.Framework. Please refer to http://msdn2.microsoft.com/en-us/library/microsoft.xna.framework.vector2.aspx for more information.

 

Gamepad Input with XNA: defined in Microsoft.xna.Framework.Input. Please refer to http://msdn2.microsoft.com/en-us/library/microsoft.xna.framework.input.aspx for more information.

 

Microsoft Cross-Platform Audio Creation Tool (XACT): This program is part of the Game Studio Express  release. Please refer to http://msdn2.microsoft.com/en-us/library/bb174772%28VS.85%29.aspx to find out more about how to work with this program.

 



This document and the related materials are developed with support from Microsoft Research Computer Gaming Initiative under the Computer Gaming Curriculum in Computer Science RFP, Award Number 15871 and 16531.


Kelvin Sung
Computing and Software Systems
University of Washington, Bothell
ksung@u.washington.edu