using
directives to the top of the class file:using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework;
#region Declarations public Texture2D Texture; private Vector2 worldLocation = Vector2.Zero; private Vector2 velocity = Vector2.Zero; private List<Rectangle> frames = new List<Rectangle>(); private int currentFrame; private float frameTime = 0.1f; private float timeForCurrentFrame = 0.0f; private Color tintColor = Color.White; private float rotation = 0.0f; public bool Expired = false; public bool Animate = true; public bool AnimateWhenStopped = true; public bool Collidable = true; public int CollisionRadius = 0; public int BoundingXPadding = 0; public int BoundingYPadding = 0; #endregion
#region Constructors public Sprite( Vector2 worldLocation, Texture2D texture, Rectangle initialFrame, Vector2 velocity) { this.worldLocation = worldLocation; Texture = texture; this.velocity = velocity; frames.Add(initialFrame); } #endregion
#region Drawing and Animation Properties public int FrameWidth { get { return frames[0].Width; } } public int FrameHeight { get { return frames[0].Height; } } public Color TintColor { get { return tintColor; } set { tintColor = value; } } public float Rotation { get { return rotation; } set { rotation = value % MathHelper.TwoPi; } } public int Frame { get { return currentFrame; } set { currentFrame = (int)MathHelper.Clamp(value, 0, frames.Count - 1); } } public float FrameTime { get { return frameTime; } set { frameTime = MathHelper.Max(0, value); } } public Rectangle Source { get { return frames[currentFrame]; } } #endregion
#region Positional Properties public Vector2 WorldLocation { get { return worldLocation; } set { worldLocation = value; } } public Vector2 ScreenLocation { get { return Camera.Transform(worldLocation); } } public Vector2 Velocity { get { return velocity; } set { velocity = value; } } public Rectangle WorldRectangle { get { return new Rectangle( (int)worldLocation.X, (int)worldLocation.Y, FrameWidth, FrameHeight); } } public Rectangle ScreenRectangle { get { return Camera.Transform(WorldRectangle); } } public Vector2 RelativeCenter { get { return new Vector2(FrameWidth / 2, FrameHeight / 2); } } public Vector2 WorldCenter { get { return worldLocation + RelativeCenter; } } public Vector2 ScreenCenter { get { return Camera.Transform(worldLocation + RelativeCenter); } } Sprite classnew Sprite class, building#endregion
#region Collision Related Properties public Rectangle BoundingBoxRect { get { return new Rectangle( (int)worldLocation.X + BoundingXPadding, (int)worldLocation.Y + BoundingYPadding, FrameWidth - (BoundingXPadding * 2), FrameHeight - (BoundingYPadding * 2)); } } #endregion
#region Collision Detection Methods public bool IsBoxColliding(Rectangle OtherBox) { if ((Collidable) && (!Expired)) { return BoundingBoxRect.Intersects(OtherBox); } else { return false; } } public bool IsCircleColliding( Vector2 otherCenter, float otherRadius) { if ((Collidable) && (!Expired)) { if (Vector2.Distance(WorldCenter, otherCenter) < (CollisionRadius + otherRadius)) return true; else return false; } else { return false; } } #endregion
#region Animation-Related Methods public void AddFrame(Rectangle frameRectangle) { frames.Add(frameRectangle); } public void RotateTo(Vector2 direction) { Rotation = (float)Math.Atan2(direction.Y, direction.X); } #endregion
Update()
and Draw()
methods to the Sprite class:#region Update and Draw Methods public virtual void Update(GameTime gameTime) { if (!Expired) { float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; timeForCurrentFrame += elapsed; if (Animate) { if (timeForCurrentFrame >= FrameTime) { if ((AnimateWhenStopped) || (velocity != Vector2.Zero)) { currentFrame = (currentFrame + 1) % (frames.Count); timeForCurrentFrame = 0.0f; } } } worldLocation += (velocity * elapsed); } } Sprite classnew Sprite class, buildingpublic virtual void Draw(SpriteBatch spriteBatch) { if (!Expired) { if (Camera.ObjectIsVisible(WorldRectangle)) { spriteBatch.Draw( Texture, ScreenCenter, Source, tintColor, rotation, RelativeCenter, 1.0f, SpriteEffects.None, 0.0f); } } } #endregion
The Sprite class is presented in one large block here because most of the code should be familiar (if slightly reorganized) from the same class in Asteroid Belt Assault. A few updates have been made to the code, however, so let's go over those changes in detail.
First, the location
member has been renamed to worldLocation
. Similarly, the Location
property has been renamed to WorldLocation
. These changes are purely for clarity, reminding us that all of our sprites are world-aligned instead of screen-aligned.
Several new member variables have been added to the class as well. If Expired
is set to true, the sprite will not be updated or drawn. In addition, the BoxCollision()
and CircleCollision()
methods will always return false
for expired sprites. If the Collidable
member is set to false, both of the collision methods will also return false.
The last pair of new members, Animate
and AnimateWhenStopped
are checked during the sprite's Update()
method. If Animate
is false, the sprite will not advance frame animations. If AnimateWhenStopped
is set to false, the sprite will not advance its frame animations if the velocity
vector is equal to Vector2.Zero
. This simply means that when the sprite is moving, its animation will play (assuming Animate
is true). When the sprite is not moving, its animation will not play.
In addition to the new member variables, the WorldLocation
property has a new counterpart called ScreenLocation
. This property uses the Camera.Transform()
method to return the screen-based location of the object and is used in the Draw()
method to determine where on the screen the sprite should be displayed.
Similarly, the Destination
property (which, in Asteroid Belt Assault, returned the rectangle on the screen that the sprite was drawn to) has been split into WorldRectangle
and ScreenRectangle
and the Center
property has been split into WorldCenter
and ScreenCenter
.
As a helper to assist in calculating the center of the sprite object, the RelativeCenter
property has been introduced, which returns a vector equal to half of the width and height of the sprite's frame rectangle. This vector points to the center of the sprite relative to its own upper left corner.
We now have both of the components we need for a "larger than the screen" world for our game, so let's add a few lines of temporary code to our project to get a feel for how they work together. Throughout the project, we will be expanding on or adding new temporary code segments to see the objects we have implemented in action.
3.15.6.77