XNA Game-Themed Assignment (XGA)

XGA-100: Implementation Guide


Kelvin Sung
Computing and Software Systems
University of Washington, Bothell
ksung@u.washington.edu
Michael Panitz
Software Programming
Cascadia Community College
mpanitz@cascadia.ctc.edu

1. Topics Covered:

This document explains some of the implementation details found in the example solution to the XGA-100 assignment module.  Please follow this link to find out more about XGA-100 assignment module and all other XGA assignments. Topics covered in this implementation guide include:

 

Pre-Requisite:

It is assumed that you have read the following documents:

  1. The XNA Installation Guide: guides you download and install the XNA SDK and Game Studio Express IDE.

  2. The XnaAssignmentBase Guide: describes how to work with the XnaAssignmentBase class.


Please download the XNA_Tutorial zip file and unzip this file. It is best to open the project in the Game Studio Express IDE and follow the source code while reading the rest of this implementation guide.

 

2. Implementation:

Now, compile and run the XNA_Tutorial application. You should see:

Notice that (note: this is the controller keyboard mapping):

Left Trigger: When depressed, the chameleon turns and face left and the circle will move left.

Right Trigger: When depressed, the chameleon turns to face right and the circle will move right.

In addition, notice that the color at the center of the circle reflects the region it is located in. This color will change as the circle center is moved across the boundary between the blue/pink regions. In this application, the two color regions are defined by two constant color rectangles.

 

The rest of this document explains how these functionality are implemented.

 


3. Images in the Content/Resources/Textures Folder:

The Resources/Textures folder (in the IDE this can be found under the  Content folder) contains two files, l_chameleon.png and r_chameleon.png. The two files represent the left (l__) facing and right (r_) facing version of the chameleon.

The above figure shows that depending on which of the left or right trigger is depressed the corresponding chameleon image will be mapped onto a square. The textured square will then overlap on top of a circle to create the effect of a "chameleon in a circle". The implementation for texture selection is explained in UpdateWorld, and the drawing operation is explained in DrawWorld.


4. The Source Code Structure:

The source code folder structure and file names are similar to that of the TemplateAssignment project discussed in the XnaAssignmentBase guide. The only difference is that, in this case, the program source code is located in the SwitchAndMod_Guide.cs file (instead of the Assignment.cs file). We are going to examine the content of this file in detailed.

 

Recall that when working with the XnaAssignmentBase class, we need to pay attention to the following 6 specific items:

  1. Declaring and using libraries.
  2. Resources folders (Fonts and Textures) and files.
  3. Subclass from XnaAssignmentBase and proper calling of the base class constructor.
  4. Override the three functions:
    1. InitializeWorld()
    2. UpdateWorld()
    3. DrawWorld()
  5. Understand and know how to use the drawing functions defined in the XnaAssignmentBase class.
  6. Know how to call the input functions to work with the XBOX controller.

Since the provided source code is a working program, the above items has all been properly taken cared for. The functionality we are interested in are implemented in items 2, 3 and 4. We will examine these functions.

 

Main Class Declaration and Construction

In the beginning of SwitchAndMode_Guide.cs file we can see:

public class SwitchAndMode_Guide : XnaAssignmentBase {

    private const float WORLD_MIN_X = 0.0f;   // lower left corner (0, 0)

    private const float WORLD_MIN_Y = 0.0f;

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

                                               

Vector2 m_Position;       // Position of the circle

Color m_UseColor;         // Color for the circle center

String m_Chameleon;       // texture name for the chameleon square

 

    float m_RectangleWidth;   // width of the two constant color rectangles

    float m_RectangleHeight;  // Height of the two constant color rectangles

 

    public SwitchAndMode_Guide() :

            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 in this case, we have defined an intuitive coordinate system where the lower-left corner is the origin (0,0), and we have defined the width of the drawing area to be 20 units.

 

4a. The InitializeWorld() function:

protected override void InitializeWorld() {

   // initialize the application state

   m_Position.X = 5.0f;

   m_Position.Y = 6.0f;

 

   m_RectangleHeight = WorldMax.Y - WorldMin.Y; // rectangle covers the height

   m_RectangleWidth = WORLD_WIDTH / 2.0f;       // width is half of area

 

   m_Chameleon = "l_chameleon";                 // init: look left

}

As shown above, we initialize the initial circle position and the width/height of the two constant color rectangles (the pink and blue rectangles in the background).  Notice that the rectangle height is the entire height of the drawing area and the width of each rectangle is half that of the drawing area width. In this way, the two rectangles will cover the entire drawing area. m_Chameleon is initialized to be the string "l_chameleon" which refers to the texture of the "l_chameleon.png" file (the left facing chameleon image).

 

4b. The UpdateWorld() function:

Recall that the UpdateWorld() function is responsible for keeping the application’s state up-to-date. In this case, we need to check the Triggers to move the circle:

protected override void UpdateWorld() {

  // Label A: Poll the left/right triggers  

   float deltaL = XanAssignmentBase.GamePad.Triggers.Left;

   float deltaR = XanAssignmentBase.GamePad.Triggers.Right;

   m_Position.X += deltaR - deltaL;

// Label B: choose the left/right chameleon texture

   if (deltaR > 0.0f)  m_Chameleon = "r_chameleon";

   else if (deltaL > 0.0f) m_Chameleon = "l_chameleon";

 

// Label C: determine the color to use for the circle center

iff (m_Position.X < m_RectangleWidth)

      m_UseColor = Color.LightBlue;

  else

    m_UseColor = Color.Pink;

  

·        Label A: We poll the left and right triggers states and use those values to update the circle’s center position. Notice that the deltaL value is subtracted from the m_Position.X. This means deltaL (left trigger state) will decrease m_Position.X, or it will move the circle towards the left.

·        Label B: We use the values of deltaL/R as a hint to determine which of the left/right chameleon texture to use. For example, a value of greater than zero signifies the right trigger is depressed and thus we should use the right-facing chameleon image.

·        Label C: We check the current circle position to determine the color to use for drawing the center of the circle.

 

Note: Very importantly, we did not issue any drawing commands! Drawing should only be performed in the DrawWorld() function.

 

4c. The DrawWorld() function:

With the instance variables properly updated in UpdateWorld(), when DrawWorld() is invoked, all we need to ensure is that the circle is properly drawn:

protected override void DrawWorld() {

   Vector2 rCenter = new Vector2(5.0f, m_RectangleHeight/2.0f);

   // Label A: Draws the two rectangle    

   DrawRectangle(rCenter, …, …, …, Color.LightBlue, Color.LightBlue, null);

   rCenter.X += m_RectangleWidth;

   DrawRectangle(rCenter, …, …, …, Color.Pink, Color.Pink, null);

 

   // Label B: draws circle with m_UseColor center and the textured rectangle

   DrawCircle(m_Position, 2.0f, 0.0f, Color.White, m_UseColor, null);

   DrawRectangle(m_Position, 3.0f, 3.0f, ,, , m_Chameleon);

}

 

·        Label A: We compute rCenter, the center position of the left rectangle, draws the left rectangle covering the entire left half of the drawing area. We then update the rCenter value to reflect the center of the right rectangle and do the same for the entire right side of the drawing area.

·        Label B: We draw the circle at m_Position. Notice that the color we use for the center of the circle is the m_UseColor that we have computed in UpdateWorld(). The rectangle is drawn with the texture m_Chameleon string after the circle. In this way, the textured rectangle will cover the circle and thus creating the "chameleon in circle" effect.

 

Note: Very importantly, we did not change any instance variables in the DrawWorld() function. Instance variables should only be changed in the UpdateWorld() function.

 


5. Important Observations:

The above implementation demonstrates:

·        User control of object: notice that the position of the circle is controlled by the user. Values from the input devices (user’s choice) are used to modify the current values of the circle.

·        Update vs Draw: once again, notice the clear separation between UpdateWorld() and DrawWorld(), one function changes the instance variables without drawing while the other function draws without changing any instance variables!

 


6. Exercises:

1.      Instead of WORLD_WIDTH of 20, change it 30. Now modify all necessary values (including rectangle width) such that the look and behavior of this program remains the same. The important lesson from this exercise is that we can implement the same functionality with different coordinate dimensions. Depending on the graphics and interaction of your applications (assignments) you should design the coordinate range/dimension accordingly.

2.      Add a third color region (e.g., LightGreen) by drawing a third rectangle covering the center third of the drawing area. Change the width of the two existing rectangles such that they only cover the left and right one-third of the drawing area. Now, in UpdateWorld(),  include the logic to compute m_UseColor for the circle such that its center color will properly reflect that of the three region as user moves the circle left/right.

 


 

7. Start the Assignment:

Here is the starter project where the students should start their work to complete the assignment.  We have isolated the logic for computing color into the BackgroundStrip.cs file such that students only need to work on this file. In addition, we have clearly identified regions where students should add in their code: it's between the note that says "STUDENTS: YOU NEED TO WRITE YOUR CODE BELOW:", and "STUDENTS: YOU NEED TO WRITE YOUR CODE ABOVE:" with . In this way students do not need to change anything except for the code that they add in order to complete the assignment.

 


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.