Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XNA 2D Camera Engine That Follows Sprite

What is the best way to create a parallax effect in an XNA game? I would like the camera to follow my sprite as it moves across the world, that way I can build in effects like zoom, panning, shake, and other effects. Anybody have a solid example of how this is done, preferably in a GameComponent?

like image 378
Khalid Abuhakmeh Avatar asked Apr 03 '09 01:04

Khalid Abuhakmeh


1 Answers

So I figured it out using a combination of the tutorials above and have created the class below. It tweens towards your target and follows it around. Try it out.

public interface IFocusable {     Vector2 Position { get; } }  public interface ICamera2D {     /// <summary>     /// Gets or sets the position of the camera     /// </summary>     /// <value>The position.</value>     Vector2 Position { get; set; }      /// <summary>     /// Gets or sets the move speed of the camera.     /// The camera will tween to its destination.     /// </summary>     /// <value>The move speed.</value>     float MoveSpeed { get; set; }      /// <summary>     /// Gets or sets the rotation of the camera.     /// </summary>     /// <value>The rotation.</value>     float Rotation { get; set; }      /// <summary>     /// Gets the origin of the viewport (accounts for Scale)     /// </summary>             /// <value>The origin.</value>     Vector2 Origin { get; }      /// <summary>     /// Gets or sets the scale of the Camera     /// </summary>     /// <value>The scale.</value>     float Scale { get; set; }      /// <summary>     /// Gets the screen center (does not account for Scale)     /// </summary>     /// <value>The screen center.</value>     Vector2 ScreenCenter { get; }      /// <summary>     /// Gets the transform that can be applied to      /// the SpriteBatch Class.     /// </summary>     /// <see cref="SpriteBatch"/>     /// <value>The transform.</value>     Matrix Transform { get; }      /// <summary>     /// Gets or sets the focus of the Camera.     /// </summary>     /// <seealso cref="IFocusable"/>     /// <value>The focus.</value>     IFocusable Focus { get; set; }      /// <summary>     /// Determines whether the target is in view given the specified position.     /// This can be used to increase performance by not drawing objects     /// directly in the viewport     /// </summary>     /// <param name="position">The position.</param>     /// <param name="texture">The texture.</param>     /// <returns>     ///     <c>true</c> if the target is in view at the specified position; otherwise, <c>false</c>.     /// </returns>     bool IsInView(Vector2 position, Texture2D texture); }  public class Camera2D : GameComponent, ICamera2D {     private Vector2 _position;     protected float _viewportHeight;     protected float _viewportWidth;      public Camera2D(Game game)         : base(game)     {}      #region Properties      public Vector2 Position     {         get { return _position; }         set { _position = value; }     }     public float Rotation { get; set; }     public Vector2 Origin { get; set; }     public float Scale { get; set; }     public Vector2 ScreenCenter { get; protected set; }     public Matrix Transform { get; set; }     public IFocusable Focus { get; set; }     public float MoveSpeed { get; set; }      #endregion      /// <summary>     /// Called when the GameComponent needs to be initialized.      /// </summary>     public override void Initialize()     {         _viewportWidth = Game.GraphicsDevice.Viewport.Width;         _viewportHeight = Game.GraphicsDevice.Viewport.Height;          ScreenCenter = new Vector2(_viewportWidth/2, _viewportHeight/2);         Scale = 1;         MoveSpeed = 1.25f;          base.Initialize();     }      public override void Update(GameTime gameTime)     {         // Create the Transform used by any         // spritebatch process         Transform = Matrix.Identity*                     Matrix.CreateTranslation(-Position.X, -Position.Y, 0)*                     Matrix.CreateRotationZ(Rotation)*                     Matrix.CreateTranslation(Origin.X, Origin.Y, 0)*                     Matrix.CreateScale(new Vector3(Scale, Scale, Scale));          Origin = ScreenCenter / Scale;          // Move the Camera to the position that it needs to go         var delta = (float) gameTime.ElapsedGameTime.TotalSeconds;          _position.X += (Focus.Position.X - Position.X) * MoveSpeed * delta;         _position.Y += (Focus.Position.Y - Position.Y) * MoveSpeed * delta;          base.Update(gameTime);     }      /// <summary>     /// Determines whether the target is in view given the specified position.     /// This can be used to increase performance by not drawing objects     /// directly in the viewport     /// </summary>     /// <param name="position">The position.</param>     /// <param name="texture">The texture.</param>     /// <returns>     ///     <c>true</c> if [is in view] [the specified position]; otherwise, <c>false</c>.     /// </returns>     public bool IsInView(Vector2 position, Texture2D texture)     {         // If the object is not within the horizontal bounds of the screen          if ( (position.X + texture.Width) < (Position.X - Origin.X) || (position.X) > (Position.X + Origin.X) )             return false;          // If the object is not within the vertical bounds of the screen         if ((position.Y + texture.Height) < (Position.Y - Origin.Y) || (position.Y) > (Position.Y + Origin.Y))             return false;          // In View         return true;     } } 

And Here is how you would use it with SpriteBatch:

spriteBatch.Begin(SpriteBlendMode.AlphaBlend,                   SpriteSortMode.FrontToBack,                   SaveStateMode.SaveState,                   Camera.Transform); spriteBatch.Draw(_heliTexture,                  _heliPosition,                  heliSourceRectangle,                  Color.White,                  0.0f,                  new Vector2(0,0),                  0.5f,                  SpriteEffects.FlipHorizontally,                  0.0f); spriteBatch.End(); 

Let Me know if this helps you out, and thanks to StackOverflow and the community. W00t!

like image 95
Khalid Abuhakmeh Avatar answered Oct 08 '22 11:10

Khalid Abuhakmeh