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

Here is the
zip file
to the source
files and compiled executable of this example.

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:

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.

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.

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.

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;

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;

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
;
instead.

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!!!

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.

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

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.

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.

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.

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)