| XNA Game-Themed CS1 Examples (XGC1) | |
|
Release 2.0 (XNA V3.1) |
|
References:
Goals:
1. Obtain the example code
When the game starts, you'll see a screen that looks similar to this:

The game behaves in a manner that is almost identical to the what was described for the previous tutorial, with one new feature:
When the game goes from goes from Novice mode to Expert mode, the game will play a sound, and increase the speed of the ball.
Internally (i.e., in a way that the player won't notice), the game will change how it keeps track of whether it's in Novice or Expert mode using an instance variable.
Let's examine the source code, feature by feature.
Let's examine the C# source code that produces the behavior we see on-screen. Since the code is nearly identical to the program that was presented in the previous tutorial, we'll leave out everything, except for code that has changed, or code that is new.
Starting with this tutorial (and increasing, as we move onwards), our program will need to know what mode the game is currently in. So instead of repeatedly asking if (m_NumBounces > EXPERT_LEVEL_BOUNCES), we would instead like to calculate this just once in each UpdateWorld, and store that result into a variable. That way, we can quickly check that variable, and not have to worry about accidentally miscalculating on subsequent times (for example, accidentally typing if (m_NumBounces < EXPERT_LEVEL_BOUNCES), which compiles, but doesn't do what we want.).
For this tutorial, we will store the mode into an instance variable that
is a string.
In computer programming, string is the term used to indicate text. In
a nutshell, we will store the string "Novice" into the variable if the game
is in Novice mode (which is how the game starts), and then store the string
"Expert" into that variable once the player has bounced the ball enough.
|
<code above this point
omitted for clarity> // collect statistics private int m_NumBounces; private String m_SkillLevel; <code below this point omitted for clarity> |
|
protected
override
void
InitializeWorld() { World.SetWorldCoordinate(new Vector2(0,0), 100.0f); // initilaize the soccer ball InitializeSoccer(); // initialize the left and right paddles m_LeftPaddle = InitializeRectangle(LEFT_PADDLE_X, PADDLE_INIT_Y, PADDLE_WIDTH, PADDLE_HEIGHT); m_RightPaddle = InitializeRectangle(RIGHT_PADDLE_X, PADDLE_INIT_Y, PADDLE_WIDTH, PADDLE_HEIGHT); // initialize statistics m_NumBounces = 0; m_SkillLevel = "Novice"; } |
|
<code above this point
omitted for clarity> // paddle colliding with the soccer BounceOffPaddles(); if (m_NumBounces > EXPERT_LEVEL_BOUNCES) { // String equality test if (m_SkillLevel == "Novice") PlayACue( "Victory");m_SkillLevel = "Expert";} EchoToBottomStatus( "[" + m_SkillLevel + "]: bounces=" + m_NumBounces);} // end of UpdateWorld |
Since m_SkillLevel variable is initialized to "Novice", we only need to change it if the player has gotten enough bounces to advance to Expert mode. This if statement will ensure that we skip all the code inside the curly braces if the player has bounced the ball (off the paddles) less than EXPERT_LEVEL_BOUNCES times.
// String equality test
if (m_SkillLevel == "Novice")
PlayACue(
"Victory");m_SkillLevel =
"Expert";}
PlayACue(
"Victory");We do this by asking 'Is the value referred to by the m_SkillLevel variable the same as the string "Novice"?', and if so, then we play the sound named "Victory". If the value referred to by the m_SkillLevel variable NOT the same, then we'll skip playing the sound.
(m_NumBounces > EXPERT_LEVEL_BOUNCES)
) , and as such, each and every time that UpdateWorld is called, if the player has bounced the ball more than EXPERT_LEVEL_BOUNCES bounces, then "Expert" will be assigned to m_SkillLevel.
| Variable | Value |
| m_NumBounces | 5 |
| m_SkillLevel | "Novice" |
When the program gets to the line
if
(m_NumBounces > EXPERT_LEVEL_BOUNCES)
we see that m_NumBounces
has the value of 5, which is exactly equal to, but not greater than
EXPERT_LEVEL_BOUNCES.
Thus, the if statement evaluates to false, everything inside the curly
braces are skipped, and the program next prints out the message
"[Novice]: bounces=5"
to the bottom status bar.
| Variable | Value |
| m_NumBounces | 6 |
| m_SkillLevel | "Novice" |
When the program gets to the line
if
(m_NumBounces > EXPERT_LEVEL_BOUNCES)
we see that m_NumBounces
has the value of 6, which is greater than
EXPERT_LEVEL_BOUNCES.
Thus, the if statement evaluates to true, everything inside the curly
braces is executed, starting with:
if (m_SkillLevel ==
"Novice")
As we can see, m_SkillLevel
does have the value
"Novice", so this also evaluates to true. As a result, the
program proceeds to execute the next line down:
PlayACue("Victory");
This line starts the 'Victory' sound playing, for 1 second.
Next, the program goes on to execute the line
m_SkillLevel =
"Expert";
which changes the variables to be:
| Variable | Value |
| m_NumBounces | 6 |
| m_SkillLevel | "Expert" |
having done everything inside the curly braces, the program next prints
out the message
"[Expert]: bounces=6" to the bottom
status bar.
| Variable | Value |
| m_NumBounces | 6 |
| m_SkillLevel | "Expert" |
What's different this time around is that m_SkillLevel
does NOT have the value
"Novice" - it has the value
"Novice" -so this evaluates to false. As a result, the
program proceeds to SKIP the next line down, and does NOT play another
sound. This is good, since we told XNA to play the sound for 1
second the last time we were in the UpdateWorld method, and this current
call to UpdateWorld is happening only .05 seconds after that previous one.
Next, the program goes on to execute the line
m_SkillLevel =
"Expert";
which does do the assignment, even though it doesn't actually change the value stored in the m_SkillLevel variable.
3. Increasing The Speed Of The Ball In Expert Mode
When the player advances to Expert mode, we want the game to change. Since the player has done well at the Novice level, we'd like to increase the difficulty of the game, in order to make sure that the game remains challenging and engaging to the player. We will do this by speeding up the ball when the game switches from Novice to Expert mode. We will do this by adjusting the starting speed of the ball to be slightly slower, and define a couple of new constants to define how much we will boost the ball's speed by.
|
<code above this point
omitted for clarity> // Ball size, position, and velocity private const float BALL_INIT_X = 50.0f; // initial ball X and Y positions private const float BALL_INIT_Y = 25.0f; private const float BALL_RADIUS = 2.5f; private const float BALL_VELOCITY_MIN_X = 0.5f; private const float BALL_VELOCITY_MAX_X = 1.1f;private const float BALL_VELOCITY_MIN_Y = BALL_VELOCITY_MIN_X / 3.0f; private const float BALL_VELOCITY_MAX_Y = BALL_VELOCITY_MAX_X / 3.0f; private const float BALL_VELOCITY_EXPERT_BOOST_X = 0.1f; private const float BALL_VELOCITY_EXPERT_BOOST_Y = BALL_VELOCITY_EXPERT_BOOST_Y / 3.0f; // Bounces for Expert level private const int EXPERT_LEVEL_BOUNCES = 5; <code below this point omitted for clarity> |
private const float BALL_VELOCITY_EXPERT_BOOST_X = 0.1f;
private const float BALL_VELOCITY_EXPERT_BOOST_Y = BALL_VELOCITY_EXPERT_BOOST_Y / 3.0f;
|
<code above this point
omitted for clarity> // paddle colliding with the soccer BounceOffPaddles(); if (m_NumBounces > EXPERT_LEVEL_BOUNCES) { // String equality test if (m_SkillLevel == "Novice") { PlayACue("Victory"); m_TheSoccer.VelocityX = m_TheSoccer.VelocityX + Math.Sign(m_TheSoccer.VelocityX) * BALL_VELOCITY_EXPERT_BOOST_X; m_TheSoccer.VelocityY = m_TheSoccer.VelocityY + Math.Sign(m_TheSoccer.VelocityY) * BALL_VELOCITY_EXPERT_BOOST_Y; } m_SkillLevel = "Expert"; }
EchoToBottomStatus("[" + m_SkillLevel + "]: bounces=" + m_NumBounces); } // end of UpdateWorld |
{
PlayACue("Victory");
m_TheSoccer.VelocityX = m_TheSoccer.VelocityX + Math.Sign(m_TheSoccer.VelocityX) * BALL_VELOCITY_EXPERT_BOOST_X;
m_TheSoccer.VelocityY = m_TheSoccer.VelocityY + Math.Sign(m_TheSoccer.VelocityY) * BALL_VELOCITY_EXPERT_BOOST_Y;
}
This is important here because we want to increase the magnitude of the ball's speed, but the exact speed may be negative, or positive. In other words, if m_TheSoccer.VelocityX is, say, -.8f, then we want to make the ball go faster in that same direction, by changing m_TheSoccer.VelocityX to -.9f. However, if we just add BALL_VELOCITY_EXPERT_BOOST_X (which was defined to be 0.1f) to m_TheSoccer.VelocityX (which is -.8f in this example), we'd end up with m_TheSoccer.VelocityX being -.7f, meaning that we just slowed the ball down, instead of speeding it up. In this case, since Math.Sign(-0.8f) returns -1, then our code will first multiply BALL_VELOCITY_EXPERT_BOOST_X by -1 (which results in -0.1f), and thus add -.1f to the X speed, making it -.9, just like we wanted.
FURTHER EXERCISES::