【问题标题】:XNA 2D Camera Engine That Follows Sprite跟随 Sprite 的 XNA 2D 相机引擎
【发布时间】:2017-05-23 03:38:48
【问题描述】:

在 XNA 游戏中创建视差效果的最佳方法是什么?我希望相机跟随我的精灵在世界各地移动,这样我就可以构建缩放、平移、抖动和其他效果等效果。任何人都有一个如何做到这一点的可靠例子,最好是在 GameComponent 中?

【问题讨论】:

    标签: c# xna camera sprite


    【解决方案1】:

    所以我结合使用上面的教程来解决这个问题,并创建了下面的类。它向您的目标补间并跟随它。试试看。

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

    下面是你将如何使用它与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();
    

    如果这对您有帮助,请告诉我,感谢 StackOverflow 和社区。哇!

    【讨论】:

    • 我知道这是一个较旧的线程,但它是一个了不起的解决方案,我很乐意实施它以更好地理解它。唯一的问题是我似乎无法让它工作。我已经连接了类的所有部分,它已经初始化,它正在更新,代码中没有抛出任何错误。但是,在运行时,此时在类更新覆盖中会引发 NullReferenceException:_position.X += (Focus.Position.X - Position.X) * MoveSpeed * delta; _position.Y += (Focus.Position.Y - Position.Y) * MoveSpeed * delta;调试器说 camera.Focus 是空的......我一直在尝试一切。有什么想法吗??
    • 哇,好久不见了。但是,如果我正确阅读了我的代码,那么您需要一个精灵来实现一个 IFocusable 接口。然后你需要将该精灵传递给相机。希望这会有所帮助。
    • 你是对的!好优雅,谢谢!我试图通过将焦点拍到 Vector2 并绕过使用界面的全部要点来强行使用它,但现在我看到了曙光!非常感谢您的回复:)
    • 如果IFocusable Focus 属性永远不应该为空,那么 ctor 最好是:Camera2D(Game game, IFocusable focused)
    • 在 Update 方法中,您可能需要在计算变换矩阵之前计算 Origin 属性。否则,使用转换的原点与基于比例的最新计算的原点之间将存在临时差异。此外,您可以只执行 Matrix.CreateScale(Scale) 而不显式创建新的 Vector3。
    【解决方案2】:

    【讨论】:

    • 酷,谢谢。我必须先看看它们,看看它们是否会起作用。
    【解决方案3】:
    【解决方案4】:

    我知道这是一个老问题,但我也有同样的问题,而且我发现了这个很棒的 Monogame 相机库,所以我想我应该分享...

    https://github.com/aloisdeniel/Comora

    安装非常简单,只需添加即可跟随精灵

    this.camera.Position = 精灵的位置;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多