XNA Game-Themed Assignment (XGA)

XGA-300: 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 sample solution to the XGA-300 assignment module.  Please follow this link to find out more about XGA-300 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 XNACS1Lib Guide: describes how to work with the XNACS1Lib class.

  3. If you have not already done so,  you may wish to look at implementation guides to earlier assignments: XGA-100, XGA-200, and here is the summary of all XGA implementation guides.


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):

Button-A: moves the girl hero character forward by some random steps.

 

The rest of this document explains how to draw the background game board and move the hero character.

 


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

This project includes 4 texture files: the gold bar, the hero, the snake, and the ladder:

    kid.png gold.png ladder.png snake.png

 

As in all texture images in XGA projects, these files are stored in the Content/Resources/Textures/ subfolder.

 

4. Coordinate and Design of the Game Board:

 


The above figure illustrates the design of the game board. In particular, notice that:

  1. Coordinate system: for the ease of programming, we have designed each game cell to be of size 1 by 1. In this case, for the 5 rows by 10 columns game board, the application dimension should be 5x10. For aesthetic reasons, it is desirable to define some boundaries between the game board  and the application window. For this reason, as illustrated at the lower-left corner of the above figure, we have defined the lower-left corner of the application window to be (-0.4, -0.4) and the width of the application window to be 10.8.  The details of the coordinate system implementation can be found in SnaleAndLadder.cs, this will be discussed later.

  2. Cell position and index: with the above coordinate design, each game cell's location and index has very simple relationships,

    1. Cell located at row=r, column=c will have its center located at (r+0.5, c+0.5) where row/column are numbers between 0 and max row/column on the game board.

    2. In a one-dimensional array the index of cell (r,c) is simply: (r * (maxColumn-1) + c).

    3. For example, as illustrated at the bottom of the above figure, the cell located at row=1, column=5 has its center located at (1.5, 5.5) and with 10 columns on the game board, the index=9+5=14.

    The details of cell position and index implementation can be found in GameBoardUI.cs and will be discussed later.

  3. Game cell : The top of the figure uses cell-42 as an example to illustrate the construction of a game cell.

    1. The cell: each game cell is drawn as a light-sea-green rectangle of 0.95 width by 0.95 height.

    2. The grid lines: The grid lines between the cells are actually background color. Since each cell rectangle is drawn at its center and the size of each rectangle is 0.05 less the the dimension of the game cell, there is a 0.1 gap between neighboring cells and thus form the grid lines.

    3. The cell number: the cell numbers are rectangles texture mapped with appropriate number images.

    4. The gold: the gold is simple a texture mapped rectangle.

    The details of game cell creation can be found in GameBoardUI.cs and will be discussed later.

  4. Hero character: The hero character is a simple texture mapped rectangle.

 

Notice that the above details were designed before the implementation of the actual assignment. In general, it is more efficient to have a detailed layout of graphical object construction before implementation.


5. The Source Code Structure:

The source code folder structure and file names are similar to that discussed in the XNACS1Lib guide. In this case, there are two important differences:

  1. SnakeAndLadder.cs: this is the main source file of the project where we subclass from and override the appropriate functions defined in the XNACS1Base class.

  2. GameBoardUI.cs: this is the class defined to capture the behavior of the game board. Recall that in XGA-100 and XGA-200 implementation guides, for simplicity and readability, all functionality were defined in the same class/file. Starting from this implementation guide, as the complexity of the applications increases we will introduce extra source code files/classes to encapsulate behaviors.

 


6. The SnakeAndLadder.cs file :

Once again, this is the subclass from XNACS1Base where the required constructor/functions are implemented:

  1. Constance and Instance Variables

  2. InitializeWorld()

  3. UpdateWorld()

 

6a. The Constance and Instance Variables:

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

public class SnakeAndLadder : XNACS1Base {

  private ... TOTAL_CELLS = 50;      // number of cells (row x column)

  private ... BORDER_SIZE = 0.4f;    // boundaries around game board

 

  private ... WORLD_MIN_X = -BORDER_SIZE;   // lower-left corner

  private ... WORLD_MIN_Y = -BORDER_SIZE;   //   is (-0.4, -0.4)

  private ... WORLD_WIDTH = 10.0f + (2*BORDER_SIZE); // compensate boundaries

 

  private GameBoardGUI m_Boardgui;          // the game board

  ...

As discussed in the design of the game board, for aesthetic reasons lower-left corner of the application window is defined to be  (-0.4, -0.4). Notice the GameBoardUI class will encapsulate the game board user interaction. The SnakeAndLadder class will forward all appropriate user commands to the m_Boardgui object.

 

6b. The InitializeWorld() function:

protected override void InitializeWorld()  {

    World.SetWorldCoordinate(new Vector2(WORLD_MIN_X, WORLD_MIN_Y), WORLD_WIDTH);

    World.SetBackgroundColor(Color.LightSkyBlue);   // background color   


    m_Boardgui = new GameBoardGUI(...);     // memory for the Gameboard

}

As always, defines the coordinate system, sets background color, allocates memory.

 

6c. The UpdateWorld() function:

protected override void UpdateWorld()  {

  if (GamePad.ButtonAClicked())  {           // A-Button clicked

      int move = 1 + RandomInt(5);           // Random between 1 to 6

      m_Boardgui.MoveBy(move);               // invoke game board

      m_Status = @"Button A ... " + move;    // status for user

  ...

Since the game board behavior is supported in the m_Boardgui object, UpdateWorld() only need to forward user's commands.

 


7. The GameBoardUI.cs file:

This class supports the game board logic and drawing. The important functions contained in this file include:

  1. Constructor: constructs the game board.

  2. MoveBy(): support movement of the hero character in the game board.

  3. GetCellPosition(int index): translates the hero position from index to 1D array to (x,y) coordinate position that is suitable for drawing.

 

The constants:

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

enum BoardCellContent {         // Game cell content

      HasGold,                  // either has gold ... or

      HasNothing                // does not have anything

};

  // Label A: instance variable describing the game board dimension

private BoardCellContent[] m_GameBoard;   // Game board is stored as a 1D array

private XNACS1Circle[] m_GoldBars;        // For showing gold bars

private int m_MaxColumn;                  // number of column on the board

private int m_TotalNumCells;              // Total number game cells

 

  // Label B: hero's position: index and (x,y) position

private int m_CurrentIndex;               // current index position of the hero

private XNACS1Circle m_Hero;             // The Kid

 

  // Label C: constants for drawing the cells

private const float SIZE = 0.95f;         // Size of each game cell

private const float LABEL_SIZE = 0.2f;    // size of number label in the cell

private static float GOLD_SIZE = 0.25f;   // size of the gold bars

    ... // offsets for number labels and the gold     

 

       Label A: here we represent the game board as 1D array.  m_MaxColumns and m_TotalNumCells define the game board dimension. m_GoldBars array will store the gold bars.

       Label B: notice that the index and position information are redundant. In our application, the m_CurrentIndex is convenient for moving the hero forward in the game board while the m_Hero is convenient for drawing and everything else (e.g., collision if/when necessary).

       Label C: These constants supports the design of the game board. Please refer to the earlier discussion for details.

 

7a. The constructor:

In the constructor of the game board, we must allocate the memory for the game cells, and initialize the location of the gold bars.

public GameBoardGUI(int numCells, int maxColumn)  {

   m_MaxColumn = maxColumn;                        // initialize the variables

   m_TotalNumCells = numCells;

   m_GameBoard = new BoardCellContent[numCells];   // allocate the array

   m_GoldBar = new XNACS1Circle[numCells];         // allocate the array

 

   // Label A: loop through all the game cells

   for (int i = 0; i < m_TotalNumCells; i++)

      m_GameBoard[i] = new BoardCellContent();

      if (RandomNumber() > 0.3f)                   // 30% chance for gold bar

          m_GameBoard[i] = BoardCellContent.HasNothing;

          m_GoldBar[i] = null;

      else

          m_GameBoard[i] = BoardCellContent.HasGold;

          ...
          m_GoldBar[i] =
new XNACS1Circle(...);
 

   // Label B: Initialize the hero position

   m_CurrentIndex = 0;                             // initial hero index is 0

   m_Hero = new XNACS1Circle(GetCellPosition(m_CurrentIndex), ...); // corresponding (x,y) pos

}

As show above after the initialization of instance variables:

       Label A: loops through each of the memory cell, allocate the memory, and with 30% of probability a gold bar may be present.

       Label B: initialization of the hero position at the 0-th position. Notice we call the GetCellPosition() to ensure that the hero's (x,y) coordinate position properly corresponds to its current index position.

 

7b. The MoveBy() function:

public void MoveBy(int num) {

    m_CurrentIndex = (m_CurrentIndex + num) % m_TotalNumCells;

    m_Hero.Center = GetCellPosition(m_CurrentIndex);

}

The single index as offset in the 1D array representing the hero's position is trivial to update for movement. Here we call the GetCellPosisiont() function to ensure hero's coordinate position is properly updated.

 

7d. The GetCellPosition() function:

private Vector2 GetCellPosition(int index)  {

   int row = index / m_MaxColumn;       // row is index div column

   int col = index % m_MaxColumn;       // col is index mod column

   Vector2 p = new Vector2();      

   p.Y = row + 0.5f;                    // X is 0.5 offset from row

   p.X = col + 0.5f;                    // Y is 0.5 offset from column

   if (0 != (row % 2))                  // if odd-row

       p.X = m_MaxColumn - p.X;         // counts backwards

    return p;

}

Get cell position translates 1D index into the corresponding 2D coordinate position. In this case,  the row number is imply index div maxColumn, and column number is simply the remainder of the same division. As discussed in the game board design, coordinate value is simply 0.5 offset away from the (row, column). The only additional detail here is that to support more graceful movement of the hero when she travels across different rows, odd-number rows count right-to-left.

  


8. Important Observations:

The above implementation demonstrates:

       Coordinate System: the choice of coordinate system allowed straightforward translation between array index, and coordinate drawing position. This greatly simplifies the logic of the application and thus the application.

       Abstraction: game board is complete self-contained. More importantly, in this application the hero is represented by a simple integer number (m_CurrentPos). This example clearly illustrate that internal representation can be drastically different from graphical display for the user.


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.