MULTIMEDIA

Microsoft XNA Game Studio 3.0 : Controlling Color (part 3)

2/16/2011 11:42:23 AM

8. Making a Proper Mood Light

The fade-up part of the mood light is very good, but you don’t want it to suddenly change from white to black each time around. What you would like is for it to fade smoothly up and down. If you were telling Mrs. Update what to do, you would say something like this:

"Make the value of redIntensity bigger each time that you are called. When the value reaches 255, start making it smaller each time you are called until it reaches 0, at which point you should start making it bigger again. Do the same with blue and green."

Mrs. Update would think about this for a while and decide that she needs to keep track of two things for each color: the current intensity value (in the range 0 to 255) and something that lets her remember whether she is counting up or counting down for that color. Then, each time she is called, she can follow a sequence like this:

  1. If we are counting up, increase the value of redIntensity.

  2. If we are counting down, decrease the value of redIntensity.

  3. If redIntensity is 255, change to counting down.

  4. If redIntensity is 0, change to counting up.

This is an algorithm. It provides a sequence of operations that is used to solve a problem. In this case, we wanted to make the value of redIntensity move up to 255 and down again in steps of 1.

Of course, Mrs. Update is not a person but a C# method, so now we have to convert these steps into C#. The first thing that we need to do is work out what data we need to store. We need the intensity value and also a way of remembering if we are counting up or down. Here’s the code that declares the needed variables:

// The Game World - our color values
byte redIntensity = 0;
bool redCountingUp = true;

You have seen the redIntensity variable before; what you haven’t seen is the way that we can set it to 0 when we declare it. The redCountingUp variable is new, though. It is of a new type (C# has hundreds of different types, you’ll be pleased to hear). This is the bool type, which is special because it can hold only two possible values: true or false. It allows programs to perform what is called Boolean algebra, which consists of calculations involving only the values true and false. Such calculations are usually used to drive decisions along the lines of "If itIsRaining is true and robWillBeGoingOutside is true, I should call the takeMyUmberella method."

In this case, the bool type is perfect because redCountingUp is either true or false and nothing else. The program uses it to make decisions in the Update method so that it can behave according to the data. This ability to make decisions is what makes computers truly useful, in that they can change what they do in response to their situation. To make decisions in your programs, you have to use conditional statements.

9. Making Decisions in Your Program

You have seen two kinds of statement so far. One calls a method to do something (you use this to call the Clear method), and the other changes the value of a variable (you use this to increase the intensity of your colors). Now you are going to use a conditional construction that can change what the program does depending on the particular situation.

9.1. Creating Conditional Statements

Figure 5 shows how a conditional construction fits together. Conditional constructions start with the word if. This is followed by a condition in brackets. The condition produces a Boolean result, which can be either true or false. You can use a variable of bool type directly here.

Figure 5. The if condition in action


If the condition is true (that is, the variable redCountingUp holds the value true in this case), the statement following the condition is performed. The result is that when this statement is obeyed, the value of redIntensity gets bigger if the program is counting up. The condition can be any value that gives a Boolean result, including this rather stupid code:

if (true) redIntensity++;

The preceding code is completely legal C# code and compiles with no problem. When the program runs, the condition is true, and the statement increases the red intensity value. This is very stupid code, though, as the test might as well not be there. You could also write the following:

if (false) redIntensity++;

In this code, the statement following the condition is never obeyed because the condition is always false. This C# code compiles all right, but if you look very closely at the Microsoft Visual Studio display, you might notice that it is trying to tell you something, as shown in Figure 6.

Figure 6. Compiler warnings


If the error window in Figure 2-10 is not displayed, you can open it by selecting the View menu and clicking Error List in that menu. Alternatively you can use the key combination Ctrl+W+E.

When the compiler has finished trying to convert your C# source code into a program that can be run on the computer, it tells you how many mistakes that it thinks it has found. There are two kinds of mistakes. An error is a mistake that prevents what you have written from being made into a program. Errors are really bad things like spelling identifiers wrong, using the wrong kind of brackets, and the like.

The other kind of mistake is called a warning. This is where the compiler thinks you might have done something wrong, but it does not prevent your program from running. Figure 2-10 shows the warning message for a program with a test for (false) in it.

What the compiler is telling you is that it has managed to work out that the statement after the test will never be reached. This is because it is impossible for the value false to be true. The compiler is warning you that although the code is legal C# code, what it does might actually not be what you want.


Note:

Our Great Programmer has very strong opinions on compiler warnings; she reckons that your code should compile with no warnings at all. Warnings usually mean that your solution is imperfect in some way, and you should always take steps to investigate and resolve them.


9.2. Adding an Else Part

The condition you have created is only half correct. If the program is not counting up, it must make the value of redIntensity smaller. You can use the -- operator to do this, but we need to add extra code to the condition. You need to add an else part. Figure 7 shows another form of the if condition, with the else part added.

Figure 7. The if condition with an else part


The two statements are separated by a new key word, else. The new code means that if the program is counting up (that is, redCountingUp is true), the value gets bigger, but if the program is counting down (that is, redCountingUp is false), the value gets smaller. The else part is optional; you must add one only if you need it.

9.3. Testing Values

The program must also manage the value in redCountingUp so that when it reaches the upper limit, it starts to count down, and when it reaches the lower limit, it starts to count up again. In other words:

  1. When redIntensity reaches 255, set redCountingUp to false.

  2. When redIntensity reaches 0, set redCountingUp to true.

To do this, you need another kind of condition, one that performs a comparison. Figure 8 shows how such comparisons are created. This performs the first of these two tests.

Figure 8. Performing a comparison using the if condition


The key to understanding what is happening is the == comparison operator. When the program evaluates this condition, the values on the left and right of the == operator are compared. If they are the same, the result of the comparison is true, and the statement that follows the condition is performed. If they are different, the result of the comparison is false, and the statement that follows the comparison is ignored.

The sequence == is the comparison operator. It is completely different from the = operator, which we know as the "gozzinta." It is important that you don’t get these two confused. Unfortunately, you have both a gozzinta and a comparison taking place in the if statement because you want to put a new value into redCountingUp if the comparison succeeds.

Fortunately, the compiler can usually detect when you use the wrong operator and produce a message. There are other comparison operators that can test to see if one value is greater or less than another; we will use these later. An if statement that uses a comparison operator can have an else part; it is just that we don’t need one here. The final code to make our red intensity value move up and down ends up as follows:

if (redIntensity == 255) redCountingUp = false;
if (redIntensity == 0) redCountingUp = true;
if (redCountingUp) redIntensity++; else redIntensity--;

The program needs a second test to change the direction of the counting when the bottom limit of the intensity value is reached. The tests are performed before the intensity value is updated. This is because when the program starts running we want it to work correctly for any initial value of redIntensity. If the starting value is 255 the program must count down. If the starting value is 0 the program must count up.


Note:


Pay very careful attention to the three statements shown in this section. Go back and read our original instructions to Mrs. Update and make sure you are absolutely clear how these have been converted into C# statements that perform the job. You will notice that Mrs. Update’s original design has had to be changed so that it works with any starting value.


10. The Completed Mood Light

You now have the code that lets you create a smoothly pulsing mood light:

// The Game World - our color values
byte redIntensity = 0;
bool redCountingUp = true;

byte greenIntensity = 0;
bool greenCountingUp = true;

byte blueIntensity = 0;
bool blueCountingUp = true;

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
ButtonState.Pressed)
this.Exit();

// Update each color in turn
if (redIntensity == 255) redCountingUp = false;
if (redIntensity == 0) redCountingUp = true;
if (redCountingUp) redIntensity++; else redIntensity--;

if (greenIntensity == 255) greenCountingUp = false;
if (greenIntensity == 0) greenCountingUp = true;
if (greenCountingUp) greenIntensity++; else greenIntensity--;

if (blueIntensity == 255) blueCountingUp = false;
if (blueIntensity == 0) blueCountingUp = true;
if (blueCountingUp) blueIntensity++; else blueIntensity--;

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
Color backgroundColor;
backgroundColor =
new Color(redIntensity, greenIntensity, blueIntensity);
graphics.GraphicsDevice.Clear(backgroundColor);

base.Draw(gameTime);
}


These versions of Update and Draw produce a program that smoothly fades the screen between black and white.



10.1. A Proper Funky Mood Light

Going from black to white and back is all very well, but it would be nice to have some additional variety to our light. It turns out that this is very easy to achieve. At the moment, the red, green, and blue intensities are all the same values, counting up from 0 to 255 and back down again. This just gives shades of gray. What you want is different combinations and the color intensities going up and down at different times. You can do this by changing the starting values of our intensity values and update directions:

byte redIntensity = 0;
bool redCountingUp = true;

byte greenIntensity = 80;
bool greenCountingUp = false;

byte blueIntensity = 160;
bool blueCountingUp = true;

Rather than all the colors starting at 0 and counting up, the green value now starts at 80 and counts down, and the blue value starts at 160. This means that instead of just different shades of gray, you now have lots of other colors being presented. This provides a very groovy display. If you change the values in your program to the ones shown in this section, you can get a much more interesting-looking display. You can even try values of your own and see what they look like.

For a much longer-lasting display, we need to change the rate at which the three colors are updated. This is not actually very hard to do, so I’ve written an "Ultimate Mood Light" that you can take a look at.



11. Finding Program Bugs

Your younger brother has been reading this book and typing in the programs on his computer. He has just come and told you that the book is rubbish because the programs don’t work. He has written an Update method and is complaining that for him the red value only gets brighter. You ask him to show you the code and you see this:

if (redIntensity == 255) redCountingUp = true;
if (redIntensity == 0) redCountingUp = true;
if (redCountingUp) redIntensity++; else redIntensity++;

At first glance, it looks fine, and the C# compiler is quite happy that it is legal, but it is obviously not working. There is a bug in the program. Note that the bug is not there because the computer has made a mistake, so the instructions themselves must be faulty. You don’t want to bother the Great Programmer, as she seems to be busy playing Halo on her Xbox, so you take a look, bearing in mind something she said recently.


Note:

A good way to find out what a program is doing is to behave like the computer and "run" the program yourself. By working through the statements by hand, keeping track of the variables and making the changes to them that the program does, you can often find out what is wrong.


Your younger brother has actually made two mistakes in copying the program from these pages. See if you can find them by working through the statements.

Figure 9 highlights the errors that your younger brother has made.

Figure 9. Finding the errors in the code


The two errors both have the same effect, they cause the screen to get brighter all the time. If you fixed only one of them the program would still appear broken.

Other  
  •  Microsoft XNA Game Studio 3.0 : Working with Colors
  •  iPhone 3D Programming : Textures and Image Capture - Creating Textures with the Camera
  •  iPhone 3D Programming : Textures and Image Capture - Dealing with Size Constraints
  •  Programming with DirectX : Game Math - Vectors
  •  iPhone 3D Programming : Textures and Image Capture - Generating and Transforming OpenGL Textures with Quartz
  •  iPhone 3D Programming : Textures and Image Capture - The PowerVR SDK and Low-Precision Textures
  •  Building LOB Applications : Using Visual Studio 2010 WCF Data Services Tooling
  •  Building LOB Applications : Accessing RESTful Data using OData
  •  Programming with DirectX : Additional Texture Mapping - Image Filters
  •  Microsoft XNA Game Studio 3.0 : Making a Game Program
  •  iPhone 3D Programming : Textures and Image Capture - Texture Compression with PVRTC
  •  iPhone 3D Programming : Textures and Image Capture - Texture Formats and Types
  •  iPhone 3D Programming : Textures and Image Capture - Fight Aliasing with Filtering
  •  iPhone 3D Programming : Textures and Image Capture - Texture Coordinates Revisited
  •  Programming with DirectX : Additional Texture Mapping - Sprites
  •  Programming with DirectX : Additional Texture Mapping - Alpha Mapping
  •  Microsoft XNA Game Studio 3.0 : Writing Your First Program (part 2) - Running the Same XNA Game on Different Devices
  •  Microsoft XNA Game Studio 3.0 : Writing Your First Program (part 1)
  •  Programming with DirectX : Shading and Surfaces - Additional Texturing Topics
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 4) - Enabling Textures with ES2::RenderingEngine
  •  
    Most View
    Silverlight : Data Binding - Validating Input for Bound Data
    Iweb And Its Replacement (Part 2)
    Zyxel WHD6215 Wireless HDMI Kit
    App Of The Week : Strokesplus
    Buying Guide: For the Compact System Builder...(Part 1) - The Z77 boards, The A75 boards
    Developing Applications for the Cloud on the Microsoft Windows Azure Platform : Accessing the Surveys Application - Geo-Location
    Tips & Tricks For iPhone And iPad – May 2013 (Part 2)
    Wireless Networking Essentials (Part 2) : Wireless Repeater, Limitation Of A Wireless Network
    Shoot Your Best-Ever Portraits (Part 1)
    Mobile Application Security : Mobile Geolocation - Geolocation Methods & Geolocation Implementation
    Top 10
    10 Contenders For The 'Ultimate Protector' Crown (Part 5) : Microsoft Security Essentials 4.1, AVG Antivirus Free 2013
    10 Contenders For The 'Ultimate Protector' Crown (Part 4) : Norton Internet Security, Avast Free Antivirus Version 7
    10 Contenders For The 'Ultimate Protector' Crown (Part 3) : Eset Smart Security 6, Kaspersky Internet Security 2013, Zonealarm Internet Security 2013
    10 Contenders For The 'Ultimate Protector' Crown (Part 2) : Bitdefender Total Security 2013, Trend Micro Maximum Security, Mcafee Internet Security 2013
    10 Contenders For The 'Ultimate Protector' Crown (Part 1)
    Sony Xperia TL - Much Improved But Still Imperfect (Part 3)
    Sony Xperia TL - Much Improved But Still Imperfect (Part 2)
    Sony Xperia TL - Much Improved But Still Imperfect (Part 1)
    Simple.TV - Transmits TV Programs To Mobile (Part 2)
    Simple.TV - Transmits TV Programs To Mobile (Part 1)