<< Chapter < Page | Chapter >> Page > |
Listing 13 . Sprite class for project XNA0132Proj.
/*Project XNA0132Proj
* This file defines a Sprite class from which a Sprite* object can be instantiated. This version supports
* collision detection based on intersecting rectangles.* It also provides an Edge property that records and
* returns the edge number if a sprite collides with an* edge. However, the edge information is available for
* only one iteration of the game loop. Normally the* value of Edge is 0. However, it changes to 1,2,3,or4
* if a sprite collides with the top, right, bottom, or* left edge of the game window.
*******************************************************/using System;
using System.Collections.Generic;using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;using Microsoft.Xna.Framework.Graphics;
namespace XNA0132Proj {class Sprite {
private int edge = 0;//new to this versionprivate Texture2D image;
private Vector2 position = new Vector2(0,0);private Vector2 direction = new Vector2(0,0);
private Point windowSize;private Random random;
double elapsedTime;//in milliseconds//The following value is the inverse of speed in
// moves/msec expressed in msec/move.double elapsedTimeTarget;
//-------------------------------------------------////New to this version.
//Edge property accessorpublic int Edge {
get {return edge;
}//end get}//end Edge property accessor
//-------------------------------------------------////Image property accessor
public Texture2D Image {get {
return image;}//end get
}//end Image property accessor//-------------------------------------------------//
//Position property accessorpublic Vector2 Position {
get {return position;
}set {
position = value;}//end set
}//end Position property accessor//-------------------------------------------------//
//WindowSize property accessorpublic Point WindowSize {
set {windowSize = value;
}//end set}//end WindowSize property accessor
//-------------------------------------------------////Direction property accessor
public Vector2 Direction {get {
return direction;}
set {direction = value;
}//end set}//end Direction property accessor
//-------------------------------------------------////Speed property accessor. The set side should be
// called with speed in moves/msec. The get side// returns speed moves/msec.
public double Speed {get {
//Convert from elapsed time in msec/move to// speed in moves/msec.
return elapsedTimeTarget / 1000;}
set {//Convert from speed in moves/msec to
// elapsed time in msec/move.elapsedTimeTarget = 1000 / value;
}//end set}//end Speed property accessor
//-------------------------------------------------////This constructor loads an image for the sprite
// when it is instantiated. Therefore, it requires// an asset name for the image and a reference to a
// ContentManager object.//Requires a reference to a Random object. Should
// use the same Random object for all sprites to// avoid getting the same sequence for different
// sprites.public Sprite(String assetName,
ContentManager contentManager,Random random) {
image = contentManager.Load<Texture2D>(assetName);
image.Name = assetName;this.random = random;
}//end constructor//-------------------------------------------------//
//This method can be called to load a new image// for the sprite.
public void SetImage(String assetName,ContentManager contentManager) {
image = contentManager.Load<Texture2D>(assetName);
image.Name = assetName;}//end SetImage
//-------------------------------------------------////This method causes the sprite to move in the
// direction of the direction vector if the elapsed// time since the last move exceeds the elapsed
// time target based on the specified speed.public void Move(GameTime gameTime) {
//New to this version//Clear the Edge property value. Edge information
// is available for only one iteration of the// game loop.
edge = 0;//Accumulate elapsed time since the last move.
elapsedTime +=gameTime.ElapsedGameTime.Milliseconds;
if(elapsedTime>elapsedTimeTarget) {
//It's time to make a move. Set the elapsed// time to a value that will attempt to produce
// the specified speed on the average.elapsedTime -= elapsedTimeTarget;
//Add the direction vector to the position// vector to get a new position vector.
position = Vector2.Add(position,direction);//Check for a collision with an edge of the game
// window. If the sprite reaches an edge, cause// the sprite to wrap around and reappear at the
// other edge, moving at the same speed in a// different direction within the same quadrant
// as before. Also set the Edge property to// indicate which edge was involved. 1 is top, 2// is right, 3 is bottom, and 4 is left.
// Note that the Edge property will be cleared// to 0 the next time the Move method is called.
if(position.X<-image.Width) {
position.X = windowSize.X;edge = 4;//collision with the left edge - new
NewDirection();}//end if
if(position.X>windowSize.X) {
position.X = -image.Width / 2;edge = 2;//collision with the right edge - new
NewDirection();}//end if
if(position.Y<-image.Height) {
position.Y = windowSize.Y;edge = 1;//collision with the top - new
NewDirection();}//end if
if(position.Y>windowSize.Y) {
position.Y = -image.Height / 2;edge = 3;//collision with the bottom - new
NewDirection();}//end if on position.Y
}//end if on elapsed time}//end Move
//-------------------------------------------------////This method determines the length of the current
// direction vector along with the signs of the X// and Y components of the current direction vector.
// It computes a new direction vector of the same// length with the X and Y components having random
// lengths and the same signs.//Note that random.NextDouble returns a
// pseudo-random value, uniformly distributed// between 0.0 and 1.0.
private void NewDirection() {//Get information about the current direction
// vector.double length = Math.Sqrt(
direction.X * direction.X +direction.Y * direction.Y);
Boolean xNegative =(direction.X<0) ? true : false;
Boolean yNegative =(direction.Y<0) ? true : false;
//Compute a new X component as a random portion of// the vector length.
direction.X =(float)(length * random.NextDouble());
//Compute a corresponding Y component that will// keep the same vector length.
direction.Y = (float)Math.Sqrt(length * length -direction.X * direction.X);
//Set the signs on the X and Y components to match// the signs from the original direction vector.
if(xNegative)direction.X = -direction.X;
if(yNegative)direction.Y = -direction.Y;
}//end NewDirection//-------------------------------------------------//
public void Draw(SpriteBatch spriteBatch) {//Call the simplest available version of
// SpriteBatch.DrawspriteBatch.Draw(image,position,Color.White);
}//end Draw method//-------------------------------------------------//
//Returns the current rectangle occupied by the// sprite.
public Rectangle GetRectangle() {return new Rectangle((int)(position.X),
(int)(position.Y),image.Width,
image.Height);}//end GetRectangle
//-------------------------------------------------////This method receives a list of Sprite objects as
// an incoming parameter. It tests for a collision// with the sprites in the list beginning with the
// sprite at the head of the list. If it detects a// collision, it stops testing immediately and
// returns a reference to the Sprite object for// which it found the collision. If it doesn't find
// a collision with any sprite in the list, it// returns null.
//A collision is called if the rectangle containing// this object's image intersects the rectangle
// containing a target sprite's image.public Sprite IsCollision(List<Sprite>target) {
Rectangle thisRectangle =new Rectangle((int)(position.X),
(int)(position.Y),image.Width,
image.Height);Rectangle targetRectangle;
int cnt = 0;while(cnt<target.Count) {
targetRectangle = target[cnt].GetRectangle();
if(thisRectangle.Intersects(targetRectangle)) {return target[cnt];}//end if
cnt++;}//end while loop
return null;//no collision detected}//end IsCollision
//-------------------------------------------------//}//end class
}//end namespace
Listing 14 . Game1 class for project XNA0132Proj.
/*Project XNA0132Proj
* This project demonstrates how to write a simple 2D* arcade style game. Ten spiders try to make it across
* a web from top to bottom in opposition to two* ladybugs. If a ladybug collides with a spider, the
* spider is eaten by the ladybug.*
* The ladybugs can be moved either with the keyboard or* the mouse. Press the arrow keys to move one of the
* ladybugs. Press the A key plus the arrow keys to move* the other ladybug.
** Press the left mouse button to drag one of the
* ladybugs with the mouse. Press the right arrow key* to drag the other ladybug with the mouse.
** If a spider makes it from the top to the bottom of
* the game window, it wraps back to the top and starts* the trip over.
** On-screen text keeps track of the number of spider
* crossings at the bottom of the game window. Note,* however, that if two spiders cross the bottom in
* very close proximity, they may not both get counted.*
* This program demonstrates how to display on-screen* text. Note however that it is necessary to create
* a font resource before you can display onscreen text.* *****************************************************/
using System;using System.Collections.Generic;
using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;using XNA0132Proj;
namespace XNA0132Proj {public class Game1 : Microsoft.Xna.Framework.Game {
GraphicsDeviceManager graphics;SpriteBatch spriteBatch;
//Use the following values to set the size of the// client area of the game window. The actual window
// with its frame is somewhat larger depending on// the OS display options. On my machine with its
// current display options, these dimensions// produce a 1024x768 game window.
int windowWidth = 1017;int windowHeight = 738;
//This is the length of the greatest distance in// pixels that any sprite will move in a single
// frame of the game loop.double maxVectorLength = 5.0;
Sprite spiderWeb;//reference to a background sprite.//References to the spiders are stored in this
// List object.List<Sprite>spiders = new List<Sprite>();
int numSpiders = 10;//Number of spiders.//The following value should never exceed 60 moves
// per second unless the default frame rate is also// increased to more than 60 frames per second.
double maxSpiderSpeed = 30;//moves per second//References to the Ladybugs are stored in this List.
List<Sprite>ladybugs = new List<Sprite>();
int numLadybugs = 2;//Max number of ladybugs//Random number generator. It is best to use a single
// object of the Random class to avoid the// possibility of using different streams that
// produce the same sequence of values.//Note that the random.NextDouble() method produces
// a pseudo-random value where the sequence of values// is uniformly distributed between 0.0 and 1.0.
Random random = new Random();//The following variable is used to count the number
// of spiders that make it past the ladybugs and// reach the bottom of the game window.
int spiderCount = 0;SpriteFont Font1;//font for on-screen text
Vector2 FontPos;//position of on-screen text//-------------------------------------------------//public Game1() {//constructor
graphics = new GraphicsDeviceManager(this);Content.RootDirectory = "Content";
//Set the size of the game window.graphics.PreferredBackBufferWidth = windowWidth;
graphics.PreferredBackBufferHeight = windowHeight;}//end constructor
//-------------------------------------------------//protected override void Initialize() {
//No initialization required.base.Initialize();
}//end Initialize//-------------------------------------------------//
protected override void LoadContent() {spriteBatch = new SpriteBatch(GraphicsDevice);
Font1 = Content.Load<SpriteFont>("Kootenay");
IsMouseVisible = true;//make mouse visible//Create a sprite for the background image.
spiderWeb =new Sprite("spiderwebB",Content,random);
spiderWeb.Position = new Vector2(0f,0f);//Instantiate all of the spiders and cause them to
// move from left to right, top to// bottom. Pass a reference to the same Random
// object to all of the sprites.for(int cnt = 0;cnt<numSpiders;cnt++) {
spiders.Add(new Sprite("blackWidowSpider",Content,random));
//Set the position of the current spider at a// random location within the game window but
// near the top of the game window.spiders[cnt].Position = new Vector2((float)(windowWidth * random.NextDouble()),
(float)((windowHeight/10) *random.NextDouble()));
//Get a direction vector for the current spider.// Make both components positive to cause the
// vector to point down and to the right.spiders[cnt].Direction = DirectionVector((float)maxVectorLength,
(float)(maxVectorLength * random.NextDouble()),false,//xNeg
false);//yNeg//Notify the spider object of the size of the
// game window.spiders[cnt].WindowSize =new Point(windowWidth,windowHeight);
//Set the speed in moves per second for the// current spider to a random value between
// maxSpiderSpeed/2 and maxSpiderSpeed.spiders[cnt].Speed = maxSpiderSpeed / 2+ maxSpiderSpeed * random.NextDouble() / 2;
}//end for loop//Instantiate all of the ladybugs.They move under
// control of the keyboard or the mouse.for(int cnt = 0;cnt<numLadybugs;cnt++) {
ladybugs.Add(new Sprite("ladybug",Content,random));
//Position the ladybugs at a random position// near the bottom of the game window.
ladybugs[cnt].Position = new Vector2(
(float)(windowWidth * random.NextDouble()),(float)(windowHeight -
ladybugs[cnt].Image.Height));
}//end for loop//Position the on-screen text.
FontPos = new Vector2(windowWidth / 2, 50);//Position the mouse pointer in the center of the
// game window.Mouse.SetPosition(windowWidth / 2,windowHeight /2);
}//end LoadContent//-------------------------------------------------//
//This method returns a direction vector given the// length of the vector, the length of the
// X component, the sign of the X component, and the// sign of the Y component. Set negX and/or negY to
// true to cause them to be negative. By adjusting// the signs on the X and Y components, the vector
// can be caused to point into any of the four// quadrants.
private Vector2 DirectionVector(float vecLen,float xLen,
Boolean negX,Boolean negY) {
Vector2 result = new Vector2(xLen,0);result.Y = (float)Math.Sqrt(vecLen * vecLen
- xLen * xLen);if(negX)
result.X = -result.X;if(negY)
result.Y = -result.Y;return result;
}//end DirectionVector//-------------------------------------------------//
protected override void UnloadContent() {//No content unload required.
}//end unloadContent//-------------------------------------------------//
protected override void Update(GameTime gameTime) {//Tell all the spiders in the list to move.
for(int cnt = 0;cnt<spiders.Count;cnt++) {
spiders[cnt].Move(gameTime);
}//end for loop//Tell each ladybug to test for a collision with a
// spider and to return a reference to the spider// if there is a collision. Return null if there is
// no collision.for(int cnt = 0;cnt<ladybugs.Count;cnt++) {
//Test for a collision between this ladybug and// all of the spiders in the list of spiders.
Sprite target =ladybugs[cnt].IsCollision(spiders);if(target != null) {
//There was a collision. The spider gets eaten.// Remove it from the list of spiders.
spiders.Remove(target);}//end if
}//end for loop//Check to see if any spiders have made it to the
// bottom edge.for(int cnt = 0;cnt<spiders.Count;cnt++) {
if(spiders[cnt].Edge == 3)
//One or more made it to the bottom edge.spiderCount += 1;
}//end for loop//The following code is used to move one or the
// other of two ladybugs using the arrow keys.// Press only the arrow keys to move one of the
// ladybugs. Press the A or a plus the arrow keys// to move the other ladybug.
//The ladybugs cannot be moved outside the game// window.
//When an arrow key is pressed, the ladybug moves//five pixels per call to the Update method.
//Get the state of the keyboard.KeyboardState keyboardState = Keyboard.GetState();
//Execute moves on one ladybug with arrow keys plus// the A or a key.
if(keyboardState.IsKeyDown(Keys.Left)&&(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[0].Position.X>0)) {
ladybugs[0].Position = new Vector2(
ladybugs[0].Position.X - 5,
ladybugs[0].Position.Y);
}//end ifif(keyboardState.IsKeyDown(Keys.Right)&&(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[0].Position.X<(windowWidth - ladybugs[1].Image.Width))) {
ladybugs[0].Position = new Vector2(
ladybugs[0].Position.X + 5,
ladybugs[0].Position.Y);
}//end ifif(keyboardState.IsKeyDown(Keys.Up)&&(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[0].Position.Y>0)) {
ladybugs[0].Position = new Vector2(
ladybugs[0].Position.X,
ladybugs[0].Position.Y - 5);
}//end ifif(keyboardState.IsKeyDown(Keys.Down)&&(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[0].Position.Y<(windowHeight - ladybugs[1].Image.Height))) {
ladybugs[0].Position = new Vector2(
ladybugs[0].Position.X,
ladybugs[0].Position.Y + 5);
}//end if//Execute moves on the other ladybug with arrow
// keys pressed but the A key not pressed.if(keyboardState.IsKeyDown(Keys.Left)&&!(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[1].Position.X>0)) {
ladybugs[1].Position = new Vector2(
ladybugs[1].Position.X - 5,
ladybugs[1].Position.Y);
}//end ifif(keyboardState.IsKeyDown(Keys.Right)&&!(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[1].Position.X<(windowWidth - ladybugs[1].Image.Width))) {
ladybugs[1].Position = new Vector2(
ladybugs[1].Position.X + 5,
ladybugs[1].Position.Y);
}//end ifif(keyboardState.IsKeyDown(Keys.Up)&&!(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[1].Position.Y>0)) {
ladybugs[1].Position = new Vector2(
ladybugs[1].Position.X,
ladybugs[1].Position.Y - 5);
}//end ifif(keyboardState.IsKeyDown(Keys.Down)&&!(keyboardState.IsKeyDown(Keys.A))&&(ladybugs[1].Position.Y<(windowHeight - ladybugs[1].Image.Height))) {
ladybugs[1].Position = new Vector2(
ladybugs[1].Position.X,
ladybugs[1].Position.Y + 5);
}//end if//The following code is used to drag one or the
// other of two ladybugs using the mouse. Press// the left mouse button to drag one of the
// ladybugs. Press the right mouse button to drag// the other ladybug.
//Get the state of the mouse.MouseState mouseState = Mouse.GetState();
//Press the left mouse button to move one ladybug.if(mouseState.LeftButton == ButtonState.Pressed) {
ladybugs[0].Position =
new Vector2(mouseState.X,mouseState.Y);}//end if
//Press the right mouse button to move the other// ladybug.
if(mouseState.RightButton == ButtonState.Pressed) {ladybugs[1].Position =new Vector2(mouseState.X,mouseState.Y);
}//end ifbase.Update(gameTime);
}//end Update method//-------------------------------------------------//
protected override void Draw(GameTime gameTime) {spriteBatch.Begin();
spiderWeb.Draw(spriteBatch);//draw background//Draw all spiders.
for(int cnt = 0;cnt<spiders.Count;cnt++) {
spiders[cnt].Draw(spriteBatch);
}//end for loop//Draw all ladybugs.
for(int cnt = 0;cnt<ladybugs.Count;cnt++) {
ladybugs[cnt].Draw(spriteBatch);
}//end for loop//Draw the output text.
string output = "";if(spiderCount == 0){
output = "Congratulations. No spiders made it to"+ " the bottom.";
}else{output = "Oops, " + spiderCount + " or more "
+ "spiders made it to the bottom.";}//end else// Find the center of the string
Vector2 FontOrigin =Font1.MeasureString(output) / 2;
// Draw the stringspriteBatch.DrawString(Font1,
output,FontPos,
Color.Yellow,0,//angle
FontOrigin,1.0f,//scale
SpriteEffects.None,0.0f);//layer depth
spriteBatch.End();base.Draw(gameTime);
}//end Draw method//-------------------------------------------------//
}//end class}//end namespace
-end-
Notification Switch
Would you like to follow the 'Xna game studio' conversation and receive update notifications?