2009-04-03 28 views
34

Cách tốt nhất để tạo hiệu ứng thị sai trong trò chơi XNA là gì? Tôi muốn máy ảnh theo dõi hình ảnh của tôi khi nó di chuyển trên toàn thế giới, theo cách đó tôi có thể tạo ra các hiệu ứng như phóng to, xoay, lắc và các hiệu ứng khác. Bất cứ ai có một ví dụ vững chắc về cách thức này được thực hiện, tốt nhất là trong một GameComponent?XNA 2D Camera Engine Follows Sprite

Trả lời

41

Vì vậy, tôi figured it out sử dụng một sự kết hợp của các hướng dẫn ở trên và đã tạo ra lớp phía dưới. Nó tweens hướng tới mục tiêu của bạn và sau nó xung quanh. Hãy dùng thử.

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

Và đây là cách bạn sẽ sử dụng nó với 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 biết nếu điều này giúp bạn ra ngoài, và nhờ StackOverflow và cộng đồng. W00t!

+0

Tôi đã thử mã này, nhưng khi tôi khởi tạo nó 'Camera2D camera = new Camera2D', tôi nhận thấy tôi cần phải vượt qua trong một biến Game. Biến đó sẽ là gì? – DMan

+4

Nếu thuộc tính Tập trung 'IFocusable' không bao giờ trống, sẽ tốt hơn nếu ctor là:' Camera2D (Trò chơi trò chơi, tập trung IFocusable) ' –

+3

Trong phương thức Cập nhật, có lẽ bạn sẽ muốn tính thuộc tính Gốc trước khi tính ma trận chuyển đổi. Nếu không, sẽ có sự chênh lệch tạm thời giữa nguồn gốc đã sử dụng phép biến đổi và nguồn gốc được tính toán mới nhất dựa trên thang đo. Ngoài ra, bạn chỉ có thể thực hiện Matrix.CreateScale (Quy mô) mà không cần tạo một Vector3 mới một cách rõ ràng. –

1

Tôi biết đó là một câu hỏi cũ nhưng tôi đã có cùng một và tôi đã tìm thấy thư viện camera Monogame tuyệt vời này vì vậy tôi nghĩ rằng tôi nên chia sẻ ...

https://github.com/aloisdeniel/Comora

Nó là rất dễ dàng để cài đặt và làm theo sprite bạn chỉ cần thêm

this.camera.Position = vị trí của sprite của bạn;