Time for action - building a new Sprite class

  1. Add a new class called "Sprite" to the Robot Rampage project.
  2. Add the following using directives to the top of the class file:
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework;
    
  3. Add declarations to the Sprite class:
    #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
    
  4. Add a constructor for the Sprite class:
    #region Constructors
    public Sprite(
    Vector2 worldLocation,
    Texture2D texture,
    Rectangle initialFrame,
    Vector2 velocity)
    {
    this.worldLocation = worldLocation;
    Texture = texture;
    this.velocity = velocity;
    frames.Add(initialFrame);
    }
    #endregion
    
  5. Add properties related to drawing and animating the sprite to the Sprite class:
    #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
    
    
  6. Add position-related properties to the Sprite class:
    #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
    
  7. Add properties related to collision detection to the Sprite class:
    #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
    
  8. Add collision detection methods to the Sprite class:
    #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
    
    
  9. Add animation-related methods to the Sprite class:
    #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
    
  10. Add the 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
    

What just happened?

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.

Visualizing the view

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.6.77