2009-04-03 7 views
34

Quelle est la meilleure façon de créer un effet de parallaxe dans un jeu XNA? Je voudrais que l'appareil photo suive mon sprite lorsqu'il se déplace à travers le monde, de cette façon je peux intégrer des effets comme le zoom, le panoramique, le tremblement et d'autres effets. Quelqu'un at-il un exemple concret de la façon dont cela est fait, de préférence dans un GameComponent?Moteur de caméra XNA 2D qui suit Sprite

Répondre

41

Je pensais que ce en utilisant une combinaison des didacticiels ci-dessus et ont créé la classe au dessous de. Il tweens vers votre cible et le suit. Essaye le.

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; 
    } 
} 

Et voici comment vous l'utiliser avec 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(); 

Faites-moi savoir si cela vous aide, et grâce à StackOverflow et la communauté. W00t!

+0

J'essayais ce code, mais quand je l'ai initialisé Camera2D camera = new Camera2D, j'ai remarqué que j'avais besoin de transmettre une variable Game. Quelle variable serait-ce? – DMan

+4

Si la propriété de focus 'IFocusable' ne doit jamais être vide, il serait préférable que le ctor soit:' Camera2D (Jeu, IFocusable focus) ' –

+3

Dans la méthode Update, vous allez probablement vouloir calculer la propriété Origin avant de calculer la matrice de transformation. Sinon, il y aura une disparité temporaire entre l'origine utilisée pour la transformation et la dernière origine calculée basée sur l'échelle. En outre, vous pouvez simplement faire Matrix.CreateScale (Scale) sans créer explicitement un nouveau Vector3. –

1

Je sais que c'est une vieille question, mais j'ai eu le même et j'ai trouvé cette grande bibliothèque de la caméra monogame si je pensais que je devrais partager ...

https://github.com/aloisdeniel/Comora

Il est vraiment facile à installer et à suivre sprite vous ne devez ajouter

this.camera.Position = position de votre sprite;