| 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 in this tutorial is very similar to the prior tutorial - there are two paddles on the screen, and the ball bounces on it's own. The right thumbstick moves the right paddle up or down and the left thumbstick controls the left paddle.
The only thing that's new is the existence of a 'Block' in the middle. The soccer balls will bounce of it, but each time they bounce off it, a 'hit counter' is incremented; the hit counter is displayed as a label on the Block. In future tutorials, the block will be deactivated after it's hit a certain number of times (meaning that the soccer ball will pass through it instead of bouncing off it). In this tutorial, we will begin to establish the groundwork for this feature, but we won't implement it in this tutorial.
1. SoccerBall.cs, Paddle.cs:
These are effectively identical to what was presented in the prior tutorial.
2. Block.cs
This class defines how the Block (that appears in the middle of the screen) behaves, and is very similar to the Paddle or SoccerBall classes. It contains named constants for the width and height of the block, along with the minimum/maximum vertical location of the block. Let's examine the rest of the class in more detail:
|
protected
XNACS1Rectangle m_Rec;
// Representation of the Block
protected
int m_HitCount = 0;
// the number of times the soccer
ball hit this block
protected
bool m_IsActive;
// the block is active
|
As you can see, the Block has an XNACS1Rectangle instance variable,
in order to display a rectangle on the screen.
You'll notice that we
also have an integer to store to how many times the soccer ball has
bounced off the block, which we initialize to zero.
Lastly, the
m_IsActive field keeps track of whether the ball can bounce off the
block (if the block is active - if m_IsActive is true), or whether the
ball will pass through the block (m_IsActive is false)
|
///
<summary>
/// Create
the a block a xPos, and random Y position (between Min_Y and Max_Y)
///
</summary>
///
<param name="xPos">X-Position
of the block.</param>
public Block(float
xPos)
{
// initialize instance variables
m_HitCount = 0;
m_IsActive = true;
Vector2 center =
new
Vector2(xPos, XNACS1Base.RandomFloat(BLOCK_POSITION_MIN_Y,
BLOCK_POSITION_MAX_Y));
m_Rec = new
XNACS1Rectangle(center,
BLOCK_WIDTH, BLOCK_HEIGHT);
m_Rec.Label = "Hit=" +
m_HitCount;
m_Rec.Texture = "Block"; }
|
Because the Block starts out active, without having been hit, we
initialize m_IsActive to true, and m_HitCount to zero:
m_HitCount = 0;
m_IsActive = true;
Next, we set up the center of Block's rectangle. We want each
block to be located at a distance xPos from the left
edge of the screen, where xPos is a parameter to the construtcor (this
will be supplied by Game1's InitializeWorld method). We want the
height to be randomly chosen to be between BLOCK_POSITION_MIN_Y and
BLOCK_POSITION_MAX_Y, which we do on the following line:
Vector2 center =
new Vector2(xPos,
XNACS1Base.RandomFloat(BLOCK_POSITION_MIN_Y,
BLOCK_POSITION_MAX_Y))
We then use that semi-random center point to create the block's
on-screen rectangle, which we then initialize with a texture and a
label:
m_Rec = new
XNACS1Rectangle(center, BLOCK_WIDTH,
BLOCK_HEIGHT);
m_Rec.Label = "Hit=" +
m_HitCount;
m_Rec.Texture = "Block";
|
///
<summary>
///
Returns if this block is capable of bouncing the soccer ball.
///
</summary>
///
<returns>true
if block can bounce soccer, otherwise false</returns>
public bool
BlockIsActive()
{
return m_IsActive;
}
///
<summary>
///
///
</summary>
///
<returns>Number
of times the block hits the soccer</returns>
public int
TotalHits()
{
return m_HitCount; } |
While these accessor methods are not currently used, we will use them in future tutorials. Each method simply returns the value of the corresponding instance variable.
|
///
<summary>
///
Collide the block with the soccer ball. bounce the soccer ball,
always bouncing horizontally only!
///
</summary>
///
<param name="theSoccer">The
soccer ball to bounce with.</param>
///
<returns>true
if collided, otherwise returns false.</returns>
public
virtual bool
CollideWithSoccer(SoccerBall
theSoccer)
{
bool hit =
false;
if (m_IsActive)
{
XNACS1Circle theBallCircle
= theSoccer.GetTheCircle();
hit = m_Rec.Collided(theBallCircle);
if (hit)
{
// make sure the ball does not
"stick" to the block
if (theBallCircle.VelocityX >
0)
{
// soccer travels towards the right
// collision should happen on the
left side
// move the soccer to just outside
of the block
theBallCircle.CenterX = m_Rec.MinBound.X -
theBallCircle.Radius;
}
else
{
theBallCircle.CenterX = m_Rec.MaxBound.X +
theBallCircle.Radius;
}
// Change soccer ball x-velocity
direction
theBallCircle.VelocityX = -theBallCircle.VelocityX;
m_HitCount++;
m_Rec.Label = "Hit=" +
m_HitCount;
}
}
return hit; } |
This method will check to see if the SoccerBall object has collided with the block, and if it has, the method will then then perform any adjustments that need to be made.
Notice how similar the logic is to the Paddle class's BounceTheSoccer method - several chunks are copied verbatim! We'll see how to factor out this duplicated in the next tutorial.
The method begins by declaring the local variable hit, which will record if the soccer ball has hit this block. The default is false, and we'll only change it if the ball has, in fact collided with this block
Next, we'll check if the block is active. If it is NOT active,
then we skip any further collision detection, and return hit
(which will be false)
if (m_IsActive)
{
If the block is active (which is how the block starts the game), we
get the soccer ball's circle, and use that to figure out if the soccer
ball has collided with the block. We'll store the result into the
hit variable, so that we return the correct value at
the end of the method.
XNACS1Circle theBallCircle =
theSoccer.GetTheCircle();
hit = m_Rec.Collided(theBallCircle);
If the active block has been hit by the soccer ball, then we use the same reasoning that we did for the Paddle class to adjust the location and speed of the soccer ball.
After that's done, we'll increment the hit count, and update the
label that is displayed on the block:
m_HitCount++;
m_Rec.Label = "Hit=" +
m_HitCount;
3. Game1.cs:
As you can see, this file is almost identical to what was
presented in the prior tutorial. The additions are a constant for the X part of
the block's location, an instance variable to keep track of the Block, a line of
code in InitializeWorld to create the Block, and a line of code in UpdateWorld
to tell the Block to check for a collision with the soccer ball. All of
these changes you should be able to understand on your own.
FURTHER EXERCISES: