XNA Game-Themed CS1 Examples ( XGC1 ) Release 2.0 (XNA V3.1) 2/8/2010
Topic: Topic.2.Input_Output_PrimitiveDataTypes
Example: Ex_12.Average

# Math Operators: Average

References:
• Pre-requisite: it is assumed that you have read through the prior tutorials, and are familiar with the concepts covered in those tutorials.
• It may be useful to refer to refer to the diagram illustrating the Draw-Update loop (which explains that your initialization code will be called once, and then the XNACS1Lib will repeatedly call your Update method (after which it will Draw the screen) ), in order to have a clear picture of how your game executes.

Goals:

• In this tutorial, we will:
• Examine several mathematical operators, including multiplication and addition
• Examine how the multiplication and addition operators can be used to calculate a percentage
• Examine how to update and change on-screen shapes in response to the player's input

1. Obtain the example code

Download and unzip the zip file and you will see an ExampleProgram folder. Open the ExampleProgram folder, the EXE folder contains the compiled program and you can double click on the .sln file to work with the source code.

Once we compile and run this project, the program displays four rectangles on the screen, each labeled with each rectangle's name, and current height.  At the bottom of the screen are instructions for playing game.  By using the left thumbstick, you can control the current height of the left-most rectangle (rectangle "A"). By using the right thumbstick, you can control the current height of the second rectangle from the left (rectangle "B")  The third rectangle from the left (labled 'Fixed') has a fixed height, meaning that the height never changes.  The height of the right-most rectangle (labeled 'Average') is the average of the heights of the first three.

Additionally, when player presses the 'Back' button (or the keyboard equivalent), the program will exit.

2. Examining The Program:

Let's examine the C# source code that produces the behavior we see on-screen

• Declaring the instance variables

We need to declare our instance variables before we can use them.

 public class Game1 : XNACS1Base {         private XNACS1Rectangle aRec;     private XNACS1Rectangle bRec;     private XNACS1Rectangle fixedRec;     private XNACS1Rectangle avgRec;
• We'll need to keep track of each of the rectangles that we see on-screen, so we declare each of them here.
• Because what we're doing is sufficiently simple, we can use local variables for everything else that we want to calculate.  As a result, we don't need to declare anything else here.
• InitializeWorld():  protected override void   InitializeWorld() {     World. SetWorldCoordinate( new Vector2 (0,0), 100.0f);     float aHeight = 15.2f;     float bHeight = 20.2f;     float fixedHeight = 27.8f;     float averageHeight; // average of the above three values     averageHeight = (aHeight + bHeight + fixedHeight) / 3.0f;     aRec = new XNACS1Rectangle ();     aRec.LowerLeft= new Vector2 (10.0f, 20.0f);     aRec.Height = aHeight;     aRec.Width = 20.0f;         bRec = new XNACS1Rectangle ();     bRec.LowerLeft = new Vector2 (30.0f, 20.0f);     bRec.Height = bHeight;     bRec.Width = 20.0f;     fixedRec = new XNACS1Rectangle ();     fixedRec.LowerLeft = new Vector2 (50.0f, 20.0f);     fixedRec.Height = fixedHeight;     fixedRec.Width = 20.0f;     fixedRec.Label = "Fixed Height=" + fixedRec.Height;     avgRec = new XNACS1Rectangle ();     avgRec.LowerLeft = new Vector2 (70.0f, 20.0f);     avgRec.Height = averageHeight;     avgRec.Width = 20.0f; }
• For this program we'll use the following strategy to initialize the game:  declare and initialize a number of local variables that will hold some of the values that we want to calculate, then initialize the rectangles like we've done previously, making sure to copy the height values from the local variables into the rectangles.
• The first thing that we do is declare the local variables that we'll make use of:

float aHeight = 15.2f;

float bHeight = 20.2f;

float fixedHeight = 27.8f;

float averageHeight; // average of the above three values

Technically, we could probably get away with not creating the first three variables, but we will do so anyways, as it will look slightly nicer when we use it to calculate the average.  Notice that we've chosen to both declare and initialize each of the first three variables on one line each.

• Next, we calculate the average of the heights of the first three rectangles, and assign that average to the averageHeight variable.
averageHeight = (aHeight + bHeight + fixedHeight) / 3.0f;

Let's examine how this works, in detail:

1. There are three types of operators: the the assignment operator, the addition operator, and the division operator (as indicated by the / symbol - note that is a FORWARD slash, and is often located left and below the enter key on the keyboard (don't confuse this with the backward slash - \ ).  The assignment operator is executed last, so that all the other math can be done, and the result assigned to the the variable as we'd expect.  Normally, the division operator is evaluated before the addition operator, but anything that's inside parentheses is evaluated first (just like in your math class - PEMDAS :) ).  So the expression that's inside the parentheses ( aHeight + bHeight + fixedHeight ) gets evaluated first. But amongst those addition operators, which one will go first?  Since addition is both associative and commutative, it doesn't really matter, mathematically speaking.  However, since the computer must do the operations in some order, C# defines that order to be left-to-right.
• A table listing the C# operators, and their order of operations, is available at http://msdn.microsoft.com/en-us/library/ms173145(VS.80).aspx .  Towards the bottom, it also explains that all operators (except the assignment operator) associate left-to-right.
• To summarize: C# will first evaluate the addition operations inside the parentheses, from left to right, then will evaluate the division operator, then will finally evaluate the assignment operator.
2. In order to do the first addition, we need to know what the values of the adjacent variables are.  C# actually knows this already (since the variables is a simple variable / value type variable, and therefore C# is actually storing the value immediately inside the variable), but we'll walk through what's going on, so that we're clear about how things are evaluated.
3. averageHeight = ( aHeight + bHeight + fixedHeight ) / 3.0f;

As explained above, the addition operators will be evaluated from left to right, so we can start by mentally replacing the two variables' names with their values.  Notice that we don't do anything with the other variables just yet.
averageHeight = ( 15.2f + 20.2f + fixedHeight ) / 3.0f;

4. averageHeight = (15.2f + 20.2f+ fixedHeight) / 3.0f;
Now that all the relevant values are known, the left-most addition operation can be carried out, resulting in 35.4
averageHeight = ( 35.4f + fixedHeight) / 3.0f;
5. averageHeight = (35.4f + fixedHeight ) / 3.0f;
Next, we'll evaluate the remaining addition operator.  However, we must again mentally replace the variable name with the actual value, giving us:
averageHeight = (35.4f + 27.8f ) / 3.0f;
6. averageHeight = (35.4f + 27.8f) / 3.0f;
Now that all the relevant values are known, the remaining addition operation can be carried out, resulting in 63.2
averageHeight = ( 63.2f ) / 3.0f;
7. averageHeight = ( 63.2f ) / 3.0f;
Since there is now just a single number remainingg inside the parentheses, we can remove them
averageHeight = 63.3f / 3.0f;
8. averageHeight = 63.2f / 3.0f;
Next, we do the (real) division operation and divide 63.2 by 3. Since at least one of those numbers is a floating point number, we will do real division, and thus end up with 21.06667 (you'll notice that since the number must be stored in a computer (that has finite memory), the number is rounded off, instead of being infinitely precise).  That results in:
averageHeight = 21.06667f ;
• In this particular case, both numbers are floating point numbers, but real division will still happen even when just one of the numbers if a floating point number.  So we would have gotten the exact same answer even if we had written
averageHeight = (aHeight + bHeight + fixedHeight) / 3 ;
• If both numbers are integers, then integer division will be performed, instead.  In that case, you do the normal division to end up with a decimal number, and then simply truncate anything after the decimal point.  For example, if we wrote the following:
averageHeight = 62 / 3 ;
we could end up assigning the number 20 to averageHeight.  62/3 is 20.06667, which gets rounded down to 20.
• Note that in this case, we will still assign 20 to averageHeight (because of the integer division operation ), even though averageHeight is a float , and can store floating-point numbers!!!
9. averageHeight = 21.06667f;
All that's left is the assignment operator, which puts the value 21.06667f into averageHeight.
• Having calculated the various numbers that we'll use, we then use our familiar code to initialize the rectangles.
• Notice that since the height of the fixed rectangle never changes, we can set the label here (and only here), since we'll never have to change it again.

UpdateWorld():

 protected override void UpdateWorld() {     if (GamePad.ButtonBackClicked())         this .Exit();     float leftThumbY = GamePad.ThumbSticks.Left.Y;     float rightThumbY = GamePad.ThumbSticks.Right.Y;     float aHeight = aRec.Height;     float bHeight = bRec.Height;     float fixedHeight = fixedRec.Height;     float averageHeight; // average of the above three values     // Accumulate height for rectangles A and B     aHeight = aHeight + leftThumbY;     bHeight = bHeight + rightThumbY;     // compute average height     averageHeight = (aHeight + bHeight + fixedHeight) / 3.0f;     // Assignment the height values to corresponding rectangles     aRec.Height = aHeight;     aRec.Label = "A Height=" + aRec.Height;     bRec.Height = bHeight;     bRec.Label = "B Height=" + bRec.Height;     avgRec.Height = averageHeight;     avgRec.Label = "Average Height=" + avgRec.Height;     EchoToBottomStatus( "LeftThumb-Y adjust A-Height; RightThumb-Y adjust B-Height" ); }
• As per normal, our game will check if the user presses the 'Back' button.  If we're going to exit, there's no sense in doing any work prior to exiting, so we check if we need to exit as the first two lines in the method
• Since most textbooks present arithmetic ("math") operators using local variables, we'll be using local variables here, too.  The hope is that your textbook will provide a solid background explanation, and this tutorial will explain the video-game specific stuff, and that what's left will be just a couple lines of code that are both explained in your textbook and shown here.
• In order to make our program look more like what you're seeing in your textbook, we will use the basic strategy of copying all the numbers that we need into local variables, then doing the math (like you're seeing in your textbook), then copy the numbers out of the local variables and back into the rectangle(s), in order to update the rectangles.
• We start by creating copies (in local variables) of the numbers that we'll need.  We basically need to know two things: the current height of rectangle A, and how much the left thumbstick is being pushed.  From that, we can figure out what the new heights of the other two rectangles should be.
• Let's start by creating local variables that will hold copies of the numbers in the thumbsticks and the rectangles' heights::

float aHeight = aRec.Height;

float bHeight = bRec.Height;

float fixedHeight = fixedRec.Height;

float averageHeight; // average of the above three values

• You'll notice that we're duplicating the names of the local variables: these variables names are exactly identical to the names of the variables in the InitializeWorld method.  This is ok, because all the variables are local variables: even though they have the same names, these variables are completely separate from the variables that were declared in the other method.
• Once we've got our local copies of the data, we can now calculate the new heights of the rectangles. Rectangles A and B are adjusted based on the thumbsticks, and the fixed height rectangle never changes.

// Accumulate height for rectangles A and B

aHeight = aHeight + leftThumbY;

bHeight = bHeight + rightThumbY;

These should all be familiar from previously covered material.

• Next, we reclcalculate the height of the 'average' rectangle, using the exact same code (and procedure) as was done in the IntitializeWorld method:

// compute average height

averageHeight = (aHeight + bHeight + fixedHeight) / 3.0f;

• Lastly, we copy all the values back into the rectangles, and update their labels:

aRec.Height = aHeight;

aRec.Label = "A Height=" + aRec.Height;

bRec.Height = bHeight;

bRec.Label = "B Height=" + bRec.Height;

avgRec.Height = averageHeight;

avgRec.Label = "Average Height=" + avgRec.Height;

• In order to try and be helpful, we also echo a brief message to the bottom status bar, telling the user how to play the game.

FURTHER EXERCISES::

1. Start from a blank starter project (1000.201, if you need it), and re-do the code from memory as much as possible.  On your first try, do what you can, and keep the above code open so that when you get stuck, you can quickly look up what you forgot (and that after you finish a line, so that you can compare your line to the 'correct' line).  On the next try, do the same thing, but try to use the finished code less.  Repeat this until you can type everything, without refering the tutorial's code.
• Repeat this exercise daily for several days, so that you really get the hang of this.  As you go on, periodically review this by re-doing this exercise.
2. Changing the Average
Start this exercise using Exercise_ 2 's starter project , which is a nearly identical copy of the project that was used in the above tutorial.
You should modify the project so that the third rectangle (the fixed height one) is no longer included in the average.
3. Weighted Average
Start this exercise using Exercise_ 3 's starter project , which is a nearly identical copy of the project that was used in the above tutorial.
You should modify the project so that the values that we're averaging are weighted, meaning that numbers we think are more important count for more.  For example, lets say that when we calculate the average, we want to add twice the height of the first rectangle, three times the height of the second rectangle, and half the height of the third (fixed) rectangle, and then still divide by the number of rectangles (i.e., still divide by three)