| 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:
As you look at the screen (and play the game), you can see that there's already a lot going on. There are a number of blocks scattered randomly across the screen. The "Enemy" soccer ball on the right is moving up and down the screen. At the bottom of the screen, you can see the "Enemy not zap" message. Every so often, you'll hear a sound as the enemy tries to zap you; the message at the bottom of the screen will briefly change to "Enemy try to send zap path!". You'll notice that the 'beam' the enemy shoots isn't nearly long enough to reach to your side of the screen.
You control the "Hero" basketball on the left side of the screen, and can move that up and down the screen. Whenever you push the 'A' button, you should hear a sound, and see two circles appear, then disappear, next to your basketball. If you push the 'B' button, everything on the screen (your basketball, the enemy soccer ball, all the blocks) are randomly placed at new heights on the screen.
The goal of the game is for you to 'zap' the enemy with a laser beam more times than the enemy zaps you with it's laser beam. You'll notice that right now neither you, nor the enemy, can actually shoot a laser beam. This is something that you'll fix, as you work your way through the chapter.
Source code to produce all of the above effects are provided for you in this tutorial - you are NOT expected to write all of the above from scratch yourself. You ARE expected to be able to understand almost everything that's provided to you, since the provided code is very similar to material that you've looked at in prior tutorials. There is a small amount of genuinely new stuff, which is what we'll look at in this tutorial.
Having said that, it is important to emphasize what you will be expected to do with this project, so that you understand what you'll need to do to extend this game in future tutorials: despite being given a lot of code, in future tutorials your job will be to add (or modify) small amounts of new code. In other words, once you get an understanding of how the provided . This is important because while the volume of code may seem overwhelming at first, the reality is that you'll be making very small, manageable changes to this game throughout this chapter. In order to make it easy to find the very small amount of code that you will need to change, those lines of code have been highlighted in yellow , below.
Also, you may wish to see the 'finished' version of the game that we will build up to in this chapter. You can find it in 490 tutorial, in this chapter.
2. Overview Of The Program:
Let's start by taking a quick look at the program as a whole. For right now, we'll focus on the familiar stuff that you already know, and leave anything that's new till later in this tutorial
|
using
System;
using
System.Collections.Generic;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Audio;
using
Microsoft.Xna.Framework.Content;
using
Microsoft.Xna.Framework.GamerServices;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Input;
using
Microsoft.Xna.Framework.Net;
using
Microsoft.Xna.Framework.Storage;
using
XNACS1Lib;
namespace
ZapGameTemplate
{
///
<summary>
///
This is the main type for your game
///
</summary>
public
class
Game1
:
XNACS1Base
{
#region
Constants for the
game
// Width of the world
const
float
WORLD_MAX_WIDTH = 200.0f;
// hero's inital position
const
float
HERO_SIZE = 3.0f;
const
float
HERO_X = WORLD_MAX_WIDTH *
0.15f;
// enemy's inital position
const
float
ENEMY_SIZE = 5.0f;
const
float
ENEMY_X = WORLD_MAX_WIDTH
* 0.85f;
const
float
ENEMY_VELOCITY_MIN = 0.2f;
const
float
ENEMY_VELOCITY_MAX = 0.8f;
const
float
ENEMY_SHOT_PROBABILITY =
0.05f;
// Block's X range
const
float
BLOCK_A_X =
WORLD_MAX_WIDTH * 0.3f;
const
float
BLOCK_B_X =
WORLD_MAX_WIDTH * 0.5f;
const
float
BLOCK_C_X =
WORLD_MAX_WIDTH * 0.7f;
const
float
BLOCK_WIDTH = 6.0f;
const
float
BLOCK_HEIGHT = 30.0f;
const
float
HERO_PATH_SIZE = 0.9f;
const
float
ENEMY_PATH_SIZE = 1.1f;
#endregion
|
|
#region
instance variables
private
int
m_HeroScore = 0;
// number of times hero zapped
enemy
private
int
m_EnemyScore = 0;
//
number of times enemy zapped hero
private
XNACS1Circle
m_Hero;
private
XNACS1Circle
m_Enemy;
private
XNACS1Rectangle
m_BlockA;
private
XNACS1Rectangle
m_BlockB;
private
XNACS1Rectangle
m_BlockC;
// For storing the primitives representing the
//
path (easy remove at each update)
private
XNACS1PrimitiveSet
m_HeroPathSet;
private
XNACS1PrimitiveSet
m_EnemyPathSet;
private
float
m_RangeMinY;
private float m_RangeMaxY; // range for defining the initial
// positions of the enemy, hero, and blocks
#endregion
|
|
protected
override
void
InitializeWorld()
{
World
.SetWorldCoordinate(
new
Vector2
(0.0f, 0.0f),
WORLD_MAX_WIDTH);
m_RangeMinY =
World
.WorldMin.Y
* 0.2f;
m_RangeMaxY =
World
.WorldMax.Y
* 0.8f;
m_HeroPathSet =
new
XNACS1PrimitiveSet
();
m_EnemyPathSet =
new
XNACS1PrimitiveSet
();
ComputeRandomWorld();
}
///
<summary>
///
Compute random positions for the Hero, Enemy, and the three
blocks.
///
Resets the m_EnemyCount back to initial count
///
</summary>
private
void
ComputeRandomWorld()
{
// Make sure AutoDrawSet is
completely clean
World
.RemoveAllFromDrawSet();
m_HeroPathSet.RemoveAllFromSet();
m_EnemyPathSet.RemoveAllFromSet();
// Add the Path draw sets to
autoRedraw
m_HeroPathSet.AddToAutoDrawSet();
m_EnemyPathSet.AddToAutoDrawSet();
m_EnemyScore = 0;
m_HeroScore = 0;
// Create Hero
Vector2
heroCenter =
new
Vector2
(HERO_X, RandomFloat(m_RangeMinY, m_RangeMaxY));
m_Hero =
new
XNACS1Circle
(heroCenter,
HERO_SIZE);
m_Hero.Label =
@"Hero"
;
m_Hero.Texture =
@"BasketBall"
;
// Create the enemy
Vector2
enemyCenter =
new
Vector2
(ENEMY_X, RandomFloat(m_RangeMinY, m_RangeMaxY));
m_Enemy =
new
XNACS1Circle
(enemyCenter,
ENEMY_SIZE);
m_Enemy.Velocity =
new
Vector2
(0, RandomFloat(ENEMY_VELOCITY_MIN,
ENEMY_VELOCITY_MAX));
m_Enemy.ShouldTravel =
true
;
m_Enemy.Label =
@"Enemy"
;
m_Enemy.Texture =
@"SoccerBall"
;
// the three blocks
m_BlockA = CreateABlock(BLOCK_A_X,
@"BlockA"
);
m_BlockB = CreateABlock(BLOCK_B_X,
@"BlockB"
);
m_BlockC = CreateABlock(BLOCK_C_X,
@"BlockC"
);
}
///
<summary>
///
Creates a blocking block, located randomly in Y, and at xPos
///
</summary>
///
<param name="xPos">
X
position of the blocking block
</param>
///
<param name="label">
label
to be associated with the created block
</param>
///
<returns>
A
blocking block somewhere in y and at xPos.
</returns>
private
XNACS1Rectangle
CreateABlock(
float
xPos,
String
label)
{
Vector2
center =
new
Vector2
(xPos, RandomFloat(m_RangeMinY, m_RangeMaxY));
XNACS1Rectangle
b =
new
XNACS1Rectangle
(center, BLOCK_WIDTH, BLOCK_HEIGHT);
b.Label = label;
World
.ClampAtWorldBound(b);
return
b;
}
|
|
protected
override
void
UpdateWorld()
{
if
(GamePad.ButtonBackClicked())
this
.Exit();
if
(GamePad.ButtonBClicked())
ComputeRandomWorld();
#region
Process the Enemy
if
(
World
.ClampAtWorldBound(m_Enemy)
!=
BoundCollideStatus
.InsideBound)
m_Enemy.VelocityY = -m_Enemy.VelocityY;
m_Enemy.Texture =
@"SoccerBall"
;
#region
determine if ENEMY should fire
// clear previous enemy path
m_EnemyPathSet.RemoveAllFromSet();
String
msg =
"Enemy not zap"
;
if
(RandomFloat() <
ENEMY_SHOT_PROBABILITY)
{
// Fire!!
PlayACue(
@"ZapPath"
);
msg =
"Enemy try to send zap
path!"
;
Vector2
EnemyBeam =
m_Enemy.MinBound;
CreateEnemyPath(EnemyBeam);
EnemyBeam.X = EnemyBeam.X - 1f;
CreateEnemyPath(EnemyBeam);
EnemyBeam.X = EnemyBeam.X - 1f;
CreateEnemyPath(EnemyBeam);
}
EchoToBottomStatus(msg);
#endregion
// enemy should fire?
#endregion
// enemy procesing
#region
process the Hero
m_Hero.CenterY += GamePad.ThumbSticks.Right.Y;
World
.ClampAtWorldBound(m_Hero);
m_Hero.Texture =
@"BasketBall"
;
// clear previous hero path
m_HeroPathSet.RemoveAllFromSet();
if
(GamePad.ButtonAClicked())
{
PlayACue(
"ZapPath"
);
// Draw two circles, for now
Vector2
HeroBeam =
m_Hero.MaxBound;
CreateHeroPath( HeroBeam);
HeroBeam.X = HeroBeam.X + 2;
CreateHeroPath(HeroBeam);
}
#endregion
EchoToTopStatus(
"Scores:
YoueScore("
+ m_HeroScore +
")
EnemyScored("
+ m_EnemyScore+
")"
);
} |
// Clear previous path
m_EnemyPathSet.RemoveAllFromSet();
if
(RandomFloat() <
ENEMY_SHOT_PROBABILITY)
{
Vector2
EnemyBeam =
m_Enemy.MinBound;
CreateEnemyPath(EnemyBeam);
EnemyBeam.X = EnemyBeam.X - 1f;
CreateEnemyPath(EnemyBeam);
HeroBeam.X = HeroBeam.X + 2;
CreateHeroPath(HeroBeam);
|
#region
utility functions
///
<summary>
///
Determins if the
input "path" circle collides with any of the three blocks
///
</summary>
///
<param name="path"></param>
///
<returns>
true: if
collide, otherwise false
</returns>
private
bool
CollidedWithBlocks(
XNACS1Circle
path)
{
return
m_BlockA.Collided(path) ||
m_BlockB.Collided(path) || m_BlockC.Collided(path);
}
///
<summary>
///
Creates a new
circle representing the path from enemy towards the hero.
///
The created circle
is added to the m_EnemyPathSet for drawing purposes.
///
</summary>
///
<param name="pos">
Current
path position (circle to be created)
</param>
///
<returns>
The newly
created circle.
</returns>
private
XNACS1Circle
CreateEnemyPath(
Vector2
pos)
{
XNACS1Circle
c =
new
XNACS1Circle
(pos,
ENEMY_PATH_SIZE);
c.OutsideColor =
Color
.Gray;
c.CenterColor =
Color
.Brown;
m_EnemyPathSet.AddToSet(c);
return
c;
}
///
<summary>
///
Creates a new
circle representing the path from the hero towards the enemy.
///
The created circle
is added to the m_HeroPathSet for drawing purposes.
///
</summary>
///
<param name="pos">
Current
path position (circle to be created)
</param>
///
<returns>
The newly
created circle.
</returns>
private
XNACS1Circle
CreateHeroPath(
Vector2
pos)
{
XNACS1Circle
c =
new
XNACS1Circle
(pos,
HERO_PATH_SIZE);
c.OutsideColor =
Color
.LightBlue;
c.CenterColor =
Color
.LightGray;
m_HeroPathSet.AddToSet(c);
return
c;
}
|
FURTHER EXERCISES::