4. Storing Data in Computer Memory
The data for each color intensity is being held in a variable of type byte. The byte
type is interesting because it uses 8 bits of computer memory to hold
the value that it is trying to represent. Computer memory is actually a
huge number of such locations, each of which is 1 byte in size. The Xbox
360 has 512 megabytes of memory. This means that the memory inside the
console has about 512 million storage locations, each of which can hold a
single byte value. The memory is addressed by number, and the compiler
generates a program that uses a particular memory location when it
accesses a particular variable. Figure 4 shows how this might work. The compiler has decided that blueIntensity is to be held in memory byte number 1003, greenIntensity in memory byte number 1004, and so on.
When the program runs, the statements that work with redIntensity, blueIntensity, and greenIntensity are directed to these locations in memory. Each data type uses a particular amount of computer memory; a byte uses a single memory location. The Color type uses at least 4 bytes of memory; other types can use a lot more. When the program needs to hold a Color value, the compiler allocates a number of adjacent memory locations.
Note:
In
XNA, we never have to worry about precisely where the compiler chooses
to put things. These issues are managed automatically and hidden from
our programs. In fact, the way things really work is a little more
complex than the explanation given, but for now, it is important for you
to remember that computer data is held in memory locations of a
particular size and that a particular number of memory locations is
available for a program to use.
The same memory locations
that store data can also be used to hold program instructions. When an
Xbox game is running, it might be that half the memory space holds the
game program code (the methods) and the other half holds the data that
is being used (the variables). When a game is showing the dreaded
"Loading" screen, the Xbox is actually transferring program code and
data values from the game disk into the memory.
5. Drawing by Using Our Color Intensity Variables
The color intensity
variables that we have created represent the amounts of red, green, and
blue that the mood light has. You can use them in your Draw method to create the color to be used to clear the screen:
class Game1 {
// The Game World - our color values
byte redIntensity ;
byte greenIntensity ;
byte blueIntensity ;
protected override void Draw(GameTime gameTime)
{
Color backgroundColor;
backgroundColor =
new Color(redIntensity, greenIntensity, blueIntensity);
graphics.GraphicsDevice.Clear(backgroundColor);
base.Draw(gameTime);
}
// TODO: Update method goes here
}
This Draw
method looks very like the previous one, except that it uses member
variables to define the color that is created rather than specifying
particular values. Note that the assignment to backgroundColor has been spread over two lines. The C# compiler is quite happy with this.
Note:
Our Great Programmer is
very keen on sensible program layout. This means not letting program
lines extend off the end of the page. She says if a line gets too long,
you should break it at a sensible point (not in the middle of an
identifier) and then continue to the next line, slightly indented. She
has personally checked all the program listings in this book to make
sure that the layout meets her exacting requirements.
6. Updating Our Colors
When the program
starts, the values of byte data members are automatically set to 0 and
the background color is set to black. If you run a program with the
preceding Draw method, you see that
the screen just goes black. What you now need to do is take control of
the update process and make the colors change over time. When an empty
project is created, XNA Game Studio creates a bare-bones Update method that contains a TODO reminding the programmer to add the required code:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back==ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
The Update method is rather similar to Draw but has an extra couple of statements in it, one of which starts with the word if. This is the part of the code that decides when the game should
end. When you ran your program, you may have noticed that pressing the
Back button on the gamepad stops the game. These two statements are the
ones that dictate that behavior.
The first statement says,
"If the Back button on the gamepad for player 1 is pressed, do the next
statement," and the second statement says, "Exit the program." Put
those together, and you get a behavior that means that when the Update
method is called, if the Back button is pressed, the program exits. You
are going to spend some time on conditions later, but for now, just
remember that if you delete these two lines from your program, it is
impossible to stop it via the Xbox gamepad. So don’t delete them.
You may be wondering who calls Update
and how often. The answers at the moment are "the XNA engine" and "60
times a second." Whenever your game is active, it needs to update the
game world. This has to happen repeatedly for a game to be any fun. The
XNA engine calls the Update method to
give it a chance to perform. In a full-blown game, this involves reading
the gamepad, moving all the objects in the game world, checking to see
if any have collided, and so on. In the mood light, the Update method just changes the color values that Draw uses to draw the display.
To start with, you are just going to make a mood light that gets steadily brighter over time, so the Update method increases the value of the red, green, and blue intensities by one each time that it is called:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back==ButtonState.Pressed)
this.Exit();
// Make each color brighter
redIntensity++;
greenIntensity++;
blueIntensity++;
base.Update(gameTime);
}
The Update method works by using the ++ operator.
An operator is something in the program that tells the compiler that
you want to perform an operation on a particular item. In this case, you
are using the operator ++ on each of the intensity variables. The item that an operator works on is called an operand. Sometimes operators work by combining operands, and sometimes they work on a single operand. The ++ operator works only on a single operand. The Update method uses it on each color in turn so that each color intensity increases by one. This means that each time the Update method is called, the display should get a little bit brighter.
If you run the program with this Update
method, you see that the display does get steadily brighter for about
four seconds. Then it goes black again. This does not seem right. One of
the
additions seems to be making the value much smaller rather than
increasing it. To understand why this is, you need to take a look at how
numbers are stored in computers.
7. Memory Overflow and Data Values
You have already seen
that byte values are actually represented by 8 memory bits. Now you need
to understand what this means and the problems that it can cause.
A bit
is the smallest unit of data that you can have. A bit is either on or
off; in other words, it can store just two different values. The two
values are often referred to as true or false. Each value is represented by a particular voltage in the memory of the Xbox, but we don’t need to worry about that in detail.
Think of a bit as a coin on a
table. The coin can be either heads or tails; that is, in one of two
possible states. If you put a second coin on the table, the two coins in
combination now have four possible states, head-head, head-tail,
tail-head, and tail-tail. Each coin that you add to the table doubles
the number of possible states (that is, when you add the coin, you can
have all the previous states with the new coin on heads plus all the
previous states with the new coin on tails).
If you do the math with
eight coins, you find that they can occupy 256 different states. So 8
data bits can hold 256 different values. One of these values is 0 (all
false or all tails), which means that the largest possible integer value
that a byte can hold is 255 (all true or all heads). When the ++
operator tries to increase the value of 255, it will produce the value
of 256, which cannot be represented by 8 bits. The addition process
would like to set the value of a ninth data bit to 1, so that it can
represent the value of 256, but there is no ninth bit to set. So what
happens is that the other 8 bits are cleared to zero. This causes the
value to wrap around, which means that the value in the byte goes back
to 0 again. The result of this is that the screen goes from maximum
brightness to minimum brightness in a single step. The technical name
for this is overflow.
One very important thing
to note here is that no error messages are produced. The computer does
not "know" that it has done anything wrong. Sometimes if your program
does something stupid, you get an error and your program stops. However,
in this case, the game does not seem to notice that you have just
fallen off the end of a byte and it continues to run. Your program may
well do the wrong thing, though. This means that your program has a bug
in it. When you create the finished mood light code, you need to make
sure that the values never "wrap around" like this.
Note:
Note that you have not
"run out of memory." Rather, the program has tried to put too much
information in a single memory location. The Xbox can work with values
much larger than 256; it does this by using multiple storage locations
to hold a single item. As an example, you have seen that the information
to describe a color fills at least four memory locations.
Note:
Our
Great Programmer finds it very amusing when people say, "The stupid
computer got it wrong." She says this is not what happens. What really
happened was that the person who wrote the program did a bad job. She
has been known to roll around on the floor laughing when people ask her,
"But why didn’t the computer notice it was wrong?" She knows that the
computer really doesn’t know or care what a program actually does. The
job of the computer is to follow the instructions that the program gives
it. The job of the programmer is to write instructions that are correct
in every scenario.