XNA Game-Themed Assignment (XGA)

XGA-200: 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 of the example solution to the XGA-200 assignment module.  Please follow this link to find out more about XGA-200 assignment module and all other XGA assignments. Topics covered by 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 XNACS1Lib Guide: describes how to work with the XNACS1Lib class.

  3. If you have never worked with XGA assignments before, here is the summary of all XGA implementation guides, in particular you may wish to begin with XGA-100 Implementation guide.


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 and you will observe an application window that looks like:

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

Left ThumbStick: The purple happy face (hero) follows the motion of the left ThumbStick.

 

In addition, notice that the white circle behind the net follows the hero around. This circle shows the net hit area. When this white circle touches the buzzing insect, the insect will disappear and a new insect will appear at a random position. If the hero's net (white circle) does not touch the insect within the pre-defined time (echoed at the bottom status line) the insect will disappear. A new insect will be generated immediately at a new random position with a random velocity.

 

The rest of this tutorial details the implementation of the above functionality.


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

This project includes 19 texture files (the textures images are downloaded from:

http://office.microsoft.com/en-us/clipart/FX101321031033.aspx?pid=CL100570201033)

 

  1. Flower textures: these textures are randomly mapped to rectangles and randomly placed in the application window.
    flower0flower1flower2flower3flower4flower5flower6

     

  2. Insect textures: in the XGA-200 assignment these images are mapped randomly to a circle to represent each new insect. In this implementation guide the image Insect7 is always used.
    Insect0 Insect1 Insect2 Insect3 Insect4 Insect5 Insect6 Insect7 Insect8 Insect9

     

  3. Hero textures (for left/right facing): depending on the position of the thumbstick, either one of these two images are mapped to a rectangle representing the hero facing left or right.
    lnet (facing left) rnet (facing right)


4. The Source Code Structure:

The source code folder structure and file names are identical to that discussed in the XNACS1Lib guide. The only difference is that, in this case, the program source code is located in the InsectsGarden.cs (instead of the Game1.cs file). We are going to examine this file in detailed.

 

Please refer to the discussion in XGA-100 XGA-100 implementation guide for the 6 specifics items that we must pay attention to when working with XNACS1Base class . With the proper settings, we will pay attention to the constants and the three sub-class responsible functions:

  1. Application state: Constants and Variables

  2. InitializeWorld()

  3. UpdateWorld()

 

4a. Application State: Constants and Variables

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

public class InsectsGarden : XNACS1Base

{

   // Label A: Constants

  private const float WorldWidth = 40.0f; // Width of world

  private const int INSECT_TIMER ...= ...          // how long insects should appear

    ...

  private const int NUM_FLOWERS = 23;     // num of background flowers

  private const float NET_POSY = 1.8f;     

  private const float NET_SIZE = 1.5f;    // position and size of the net

  

  // Label B-1: Information on the hero (purple happy face)

  private XNACS1Rectangle m_Her;          // The Hero 

  private XNACS1Circle m_Net;             // The net

  //   

  // Label B-2: Insect position, length of appearance and num touched

  private XNACS1Circle m_Insect;            // the insect

  private int m_InsectTimer;              // cycles till generate new insect

  private int m_NumTouched;               // count of insects touched by net


}

There are two categories in the declaration of the main class are: constants (Label A), and instance variables (Labels B):

 

Constants:

·       Label A: Typically the width of the world (WorldWidth) is defined here. In this case, we also define parameters for determining how long insects will appear (INSECT_TIMER), and the net position (NET_POSY) and size (NET_SIZE)with respect to the hero position.

 

Instance Variables:

·       Label B-1: Parameters for the hero. In this case we want to keep track of the hero (m_Hero) and the net (m_Net) we want to use (left or right) to represent the hero. In a larger application, we would abstract the hero parameters into a separate class. In this case, all variables are kept in the same file for readability and for simplicity.

·       Label B-2: Parameters for supporting the insect. m_Insect is the insect, m_InsectTimer is the remaining time this insect will be shown, and m_NumTouched is number of times the white circle above the hero has touched the insect. During each UpdateWorld function call, conditions of the application are analyze and these parameters are updated. Notice that the first two parameters (m_Insect, and m_InsectTimer) are designed to describe the behavior of an insect and should really be in a separate class (as in the case of ExampleSolution for InsectGarden).

 

4b. The InitializeWorld() function:

protected override void InitializeWorld() {

    // Label A: define coordinate and background color

    World.SetWorldCoordinate(new Vector2(-1.0f, -1.0f), WorldWidth);

    XNACS1Base.SetBackgroundColor(Color.LawnGreen);

 

    // Label B: Flower initialization

    for (int i = 0; i < NUM_FLOWERS; i++)  {

       float x = RandomFloat(WorldMax.X);    // Random x/y position in the window

       float y = 0.5f + RandomFloat(WorldMax.Y - 1.5f);

       String tex = "flower" + RandomInt(6); // Texture image name      

       XNACS1Rectangle aFlower = new XNACS1Rectangle(new Vector2(x, y), ..., tex);

    }

 

    // Label C: The Hero

    Vector2 pos = new Vector2(WorldMax.X / 2.0f, WorldMax.Y / 2.0f);

    m_Hero = new XNACS1Rectangle(pos, 4.0f, 4.0f, "lnet");

   

    // Label D: The Net
    pos.Y += NET_POSY;

    m_Net = new XNACS1Circle(pos, NET_SIZE);

    m_Net.CenterColor = Color.White;

    m_Net.OutsideColor = Color.White;

 

    // Label E: The Insect

    m_Insect = null;

    m_InsectTimer = 0;

    m_NumTouched = 0;

As always, in InitializeWorld() we allocate memory and initialize all instance variables:

·       Label A: This is always the first operation we perform, defines the coordinate system and, when desired, sets the background color. 

·       Label B: Here we generate the randomly distributed flowers in the background. We loop through and generate random positions inside the application window, and then we compose the texture image file name by generating a random integer between zero to six. In this way,  one of the seven texture image ("flower0" to "flower6") will be used.

·       Label C: This is the hero, initialized to locate in the center of the application window facing left (with the "lnet" texture file).

·       Label D: Since we are only interested in "netting" the insect when the "net" area touches the insect, we will define a circle in the "net" area of the hero and test for this net's intersection with the insect.

·       Label E: These are the information for the insect including: the primitive, how long the insect will remain in the window, and number of times the insect has been netted.  Notice that we have chose to initialize the insect to "null", actual memory allocation will occur during UpdateWorld().

 

4c. 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 (Label A) check the ThumbStick (moving the hero), (Label B) test for net touching the insect, and  (Label C) create new insect when necessary.  Here are the details:

protected override void UpdateWorld() {

    ... // Check for exit (B-button pushed)

  // Label A: Polling thumbstick state and update hero position

    Vector2 delta = XNACS1Base.GamePad.ThumbSticks.Left;         

           ...  // determine left/right for left/right image, refer to:

       ...  //     XGA-100 Implementation Guide

           ...  // for explanations on similar implementation.

    m_HeroPos += delta * 0.5f;   // Move at constant speed

           ... // Check to ensure hero is within the world bound.

 

  // Label B: Checking the insect: 1. timer condition 2. touched by net

    if (m_InsectTimer > 0) {                 // Says: insect is visible

        m_InsectTimer--;                     // count-down to generate new insect

        Vector2 ... buzz = ... ;                 // compute a small random buzz velocity

        // Insect's flying updated automatically because ShouldTravel is true

        m_Insect.Center += buzz;             // small buzz movement

                  ...   // make sure insect does not leave the world bound

 

        // Label B-1: Checking insect touched by ne

        if ( m_Net.Collided(m_Insect)) {    

             m_InsectTimer = -1;            // current insect expires

             m_NumTouched++;                // increase count

                   ...  

  // Label C: Create new Insect if necessary

    if (m_InsectTimer <= 0) {               // current insect has expired

        if (null != m_Insect)       

             m_Insect.RemoveFromAutoDrawSet(); // should not draw this anymore

        Vector2 pos = ... ;                              // randomly place one

        m_Insect.Velocity = ...;               // random velocity
       
m_Insect.ShouldTravel = true;   // update position by velocity automatically

        m_InsectTimer = m_Rand.Next(INSECT_TIMER...); // random count-down timer

     ...          

·       Label A: delta is a 2D vector (X/Y) of values between -1 to 1 reflecting the relative position of the left thumbstick. A thumbstick in resting position will return (0,0). Here we simply use the thumbstick state to change the hero's position. The setting of the left/right image for hero is similar to the setting of chameleon images in XGA-100: Implementation Guide.

·       Label B: m_InsectTimer tells us how much longer current insect will remain on the window. When this value is larger than zero, the insect's position will automatically be updated by its velocity (because ShouldTravel is true), and we make sure the results of the update will not move the insect off the application window. buzz is a small random velocity added to the velocity to create the insect buzzing sensation.

·       Label B-1: When m_Net touches the insect, we approximate that the net has touched the insect and update the corresponding states (m_NumTouched, and m_InsectTimer).

·       Label C: m_InsectTimer of less than zero signifies current insect display timer has expired (either due to the length of appearance or it has been touched by the net). In this case, we must remove current insect from the AutoDraw set, and then create a new insect with corresponding randomness. Notice that the ShouldTravel attribute of the insect is set to true such that the insect will travel automatically according to its velocity.

 

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.