XNA 2D 相机 - 如何将其锁定/居中到动画精灵?

发布于 2024-10-11 20:03:33 字数 5717 浏览 4 评论 0原文

嘿,我试图让我的相机跟随我的精灵,由于某种原因,精灵总是比我的相机移动得更快,而我的相机无法夹在屏幕上。我想让摄像机始终以精灵为中心,并随着他的移动而跟随他。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace wintertermrpg
{
    public class AnimatedSprite
    {
        public enum Facing
        {
            Left,
            Right,
            Up,
            Down
        }
        public Facing facingDirection;

        public Dictionary<string, FrameAnimation> Animations = new Dictionary<string,     FrameAnimation>();
        Camera cam = new Camera();
        public Vector2 Position = Vector2.Zero;
        Texture2D texture;
        public bool IsCharacter = false;
        public bool isAnimating = true;
        string animationName = null;
        float speed = 2f;

        public float Speed
        {
            get { return speed; }
            set { speed = Math.Max(value, .1f); }
        }

        public string CurrentAnimationName
        {
            get { return animationName; }
            set
            {
                if (Animations.ContainsKey(value))
                    animationName = value;
            }
        }

        public Vector2 OriginOffset = Vector2.Zero;
        public Vector2 Origin
        {
            get { return Position + OriginOffset; }
        }

        public Vector2 Center
        {
            get
            {
                return Position + new Vector2(
                   CurrentAnimation.currentRect.Width / 2,
                   CurrentAnimation.currentRect.Height / 2);
            }
        }

        public FrameAnimation CurrentAnimation
        {
            get
            {
                if (!string.IsNullOrEmpty(animationName))
                    return Animations[animationName];
                else
                    return null;
            }
        }

        public AnimatedSprite(Texture2D texture, bool isCharacter)
        {
            this.texture = texture;
            IsCharacter = isCharacter;
        }

        public AnimatedSprite(Texture2D texture, bool isCharacter, Camera cam)
        {
            this.texture = texture;
            IsCharacter = isCharacter;
            this.cam = cam;
        }

        public void clampToArea(int width, int height)
        {
            if (Position.X < 0)
                Position.X = 0;
            if (Position.Y < 0)
                Position.Y = 0;
            if (Position.X > width - CurrentAnimation.currentRect.Width)
                Position.X = width - CurrentAnimation.currentRect.Width;
            if (Position.Y > height - CurrentAnimation.currentRect.Height)
                Position.Y = height - CurrentAnimation.currentRect.Height;
        }

        private void updateSpriteAnimation(Vector2 motion)
        {
            float motionAngle = (float)Math.Atan2(motion.Y, motion.X);

            if (motionAngle >= -MathHelper.PiOver4 &&
                motionAngle <= MathHelper.PiOver4)
                CurrentAnimationName = "Right";
            else if (motionAngle >= -MathHelper.PiOver4 &&
                motionAngle <= 3f * MathHelper.PiOver4)
                CurrentAnimationName = "Down";
            else if (motionAngle <= -MathHelper.PiOver4 &&
                motionAngle >= -3f * MathHelper.PiOver4)
                CurrentAnimationName = "Up";
            else
                CurrentAnimationName = "Left";
        }

        public void update(GameTime gameTime)
        {
            GamePadState state = GamePad.GetState(PlayerIndex.One);
            if (IsCharacter)
            {
                Vector2 movement = Vector2.Zero;
                if (state.ThumbSticks.Left.X < 0)
                {
                    movement.X--;
                    facingDirection = Facing.Left;
                }
                if (state.ThumbSticks.Left.X > 0)
                {
                    movement.X++;
                    facingDirection = Facing.Right;
                }
                if (state.ThumbSticks.Left.Y > 0)
                {  
                    movement.Y--;
                    facingDirection = Facing.Up;
                }
                if (state.ThumbSticks.Left.Y < 0)
                {
                    movement.Y++;
                    facingDirection = Facing.Down;
                }
                if (movement != Vector2.Zero)
                {
                    movement.Normalize();
                    Position += movement;
                    cam.Pos = Position;
                    updateSpriteAnimation(movement);
                    isAnimating = true;
                }
                else
                    isAnimating = false;

            }

            if (!isAnimating)
                return;
            FrameAnimation animation = CurrentAnimation;

            if (animation == null)
            {
                if (Animations.Count > 0)
                {
                    string[] keys = new string[Animations.Count];
                    Animations.Keys.CopyTo(keys, 0);
                    animationName = keys[0];
                    animation = CurrentAnimation;
                }
                else
                    return;
            }
            animation.Update(gameTime);

        }

        public void draw(SpriteBatch sb)
        {
            FrameAnimation animation = CurrentAnimation;
            if (animation != null)
            {
                sb.Draw(texture, Position, animation.currentRect, Color.White);
            }
        }
    }
}

Hey I'm trying to make my camera follow my sprite and for some reason the sprite is always moving faster than my camera and my camera is unable to clamp to the screen. I would like to make it so that the camera is constantly centered on the sprite and follows him as he moves.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace wintertermrpg
{
    public class AnimatedSprite
    {
        public enum Facing
        {
            Left,
            Right,
            Up,
            Down
        }
        public Facing facingDirection;

        public Dictionary<string, FrameAnimation> Animations = new Dictionary<string,     FrameAnimation>();
        Camera cam = new Camera();
        public Vector2 Position = Vector2.Zero;
        Texture2D texture;
        public bool IsCharacter = false;
        public bool isAnimating = true;
        string animationName = null;
        float speed = 2f;

        public float Speed
        {
            get { return speed; }
            set { speed = Math.Max(value, .1f); }
        }

        public string CurrentAnimationName
        {
            get { return animationName; }
            set
            {
                if (Animations.ContainsKey(value))
                    animationName = value;
            }
        }

        public Vector2 OriginOffset = Vector2.Zero;
        public Vector2 Origin
        {
            get { return Position + OriginOffset; }
        }

        public Vector2 Center
        {
            get
            {
                return Position + new Vector2(
                   CurrentAnimation.currentRect.Width / 2,
                   CurrentAnimation.currentRect.Height / 2);
            }
        }

        public FrameAnimation CurrentAnimation
        {
            get
            {
                if (!string.IsNullOrEmpty(animationName))
                    return Animations[animationName];
                else
                    return null;
            }
        }

        public AnimatedSprite(Texture2D texture, bool isCharacter)
        {
            this.texture = texture;
            IsCharacter = isCharacter;
        }

        public AnimatedSprite(Texture2D texture, bool isCharacter, Camera cam)
        {
            this.texture = texture;
            IsCharacter = isCharacter;
            this.cam = cam;
        }

        public void clampToArea(int width, int height)
        {
            if (Position.X < 0)
                Position.X = 0;
            if (Position.Y < 0)
                Position.Y = 0;
            if (Position.X > width - CurrentAnimation.currentRect.Width)
                Position.X = width - CurrentAnimation.currentRect.Width;
            if (Position.Y > height - CurrentAnimation.currentRect.Height)
                Position.Y = height - CurrentAnimation.currentRect.Height;
        }

        private void updateSpriteAnimation(Vector2 motion)
        {
            float motionAngle = (float)Math.Atan2(motion.Y, motion.X);

            if (motionAngle >= -MathHelper.PiOver4 &&
                motionAngle <= MathHelper.PiOver4)
                CurrentAnimationName = "Right";
            else if (motionAngle >= -MathHelper.PiOver4 &&
                motionAngle <= 3f * MathHelper.PiOver4)
                CurrentAnimationName = "Down";
            else if (motionAngle <= -MathHelper.PiOver4 &&
                motionAngle >= -3f * MathHelper.PiOver4)
                CurrentAnimationName = "Up";
            else
                CurrentAnimationName = "Left";
        }

        public void update(GameTime gameTime)
        {
            GamePadState state = GamePad.GetState(PlayerIndex.One);
            if (IsCharacter)
            {
                Vector2 movement = Vector2.Zero;
                if (state.ThumbSticks.Left.X < 0)
                {
                    movement.X--;
                    facingDirection = Facing.Left;
                }
                if (state.ThumbSticks.Left.X > 0)
                {
                    movement.X++;
                    facingDirection = Facing.Right;
                }
                if (state.ThumbSticks.Left.Y > 0)
                {  
                    movement.Y--;
                    facingDirection = Facing.Up;
                }
                if (state.ThumbSticks.Left.Y < 0)
                {
                    movement.Y++;
                    facingDirection = Facing.Down;
                }
                if (movement != Vector2.Zero)
                {
                    movement.Normalize();
                    Position += movement;
                    cam.Pos = Position;
                    updateSpriteAnimation(movement);
                    isAnimating = true;
                }
                else
                    isAnimating = false;

            }

            if (!isAnimating)
                return;
            FrameAnimation animation = CurrentAnimation;

            if (animation == null)
            {
                if (Animations.Count > 0)
                {
                    string[] keys = new string[Animations.Count];
                    Animations.Keys.CopyTo(keys, 0);
                    animationName = keys[0];
                    animation = CurrentAnimation;
                }
                else
                    return;
            }
            animation.Update(gameTime);

        }

        public void draw(SpriteBatch sb)
        {
            FrameAnimation animation = CurrentAnimation;
            if (animation != null)
            {
                sb.Draw(texture, Position, animation.currentRect, Color.White);
            }
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

打小就很酷 2024-10-18 20:03:33

您的相机需要为 SpriteBatch.Begin 方法生成视图矩阵。视图矩阵必须进行两次平移。

  1. 从顶部翻译原点
    左边到窗口的中心。
    (添加半视图大小)
  2. 翻译一下
    角色位于中心
    窗户的。 (减去字符
    位置)

以下代码显示了执行此操作的相机类:

using Microsoft.Xna.Framework;

namespace wintertermrpg
{
    public class Camera
    {
        public Matrix viewMatrix;
        private Vector2 m_position;
        private Vector2 m_halfViewSize;

        public Camera(Rectangle clientRect)
        {
            m_halfViewSize = new Vector2(clientRect.Width * 0.5f, clientRect.Height * 0.5f);
            UpdateViewMatrix();
        }

        public Vector2 Pos
        {
            get
            {
                return m_position;
            }

            set
            {
                m_position = value;
                UpdateViewMatrix();
            }
        }

        private void UpdateViewMatrix()
        {
            viewMatrix = Matrix.CreateTranslation(m_halfViewSize.X - m_position.X, m_halfViewSize.Y - m_position.Y, 0.0f);
        }
    }
}

然后您只需在 SpriteBatch.Begin 方法中设置视图矩阵即可:

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, m_camera.viewMatrix);

Your camera needs to generate a view matrix for the SpriteBatch.Begin method. The view matrix must make two translations.

  1. Translate the origin from the top
    left to the center of the window.
    (Add half view size)
  2. Translate so
    that the character is at the center
    of the window. (Subtract character
    position)

The following code shows a camera class that does this:

using Microsoft.Xna.Framework;

namespace wintertermrpg
{
    public class Camera
    {
        public Matrix viewMatrix;
        private Vector2 m_position;
        private Vector2 m_halfViewSize;

        public Camera(Rectangle clientRect)
        {
            m_halfViewSize = new Vector2(clientRect.Width * 0.5f, clientRect.Height * 0.5f);
            UpdateViewMatrix();
        }

        public Vector2 Pos
        {
            get
            {
                return m_position;
            }

            set
            {
                m_position = value;
                UpdateViewMatrix();
            }
        }

        private void UpdateViewMatrix()
        {
            viewMatrix = Matrix.CreateTranslation(m_halfViewSize.X - m_position.X, m_halfViewSize.Y - m_position.Y, 0.0f);
        }
    }
}

Then you just need to set the view matrix in the SpriteBatch.Begin method:

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, m_camera.viewMatrix);
时光礼记 2024-10-18 20:03:33

对于您正在尝试做的事情,这可能是一个更简单的解决方案。

将您的角色放置在屏幕上一个看不见的盒子内。每当角色试图移出此边界框时,您就会将关卡滚动到他的动作。如果您希望摄像机绝对聚焦在您的角色上,您只需滚动角色周围的关卡即可。您仍然需要跟踪屏幕上的字符位置和关卡的偏移滚动。如果您同时拥有这两者,您就知道您的角色在“关卡”中的哪个位置会发生碰撞。

如果这不是您想要的,我很抱歉,但这是一种更简单的方法。

Here might be a simpler solution to what you are trying to do.

Have your character positioned on the screen inside an invisible box. Whenever the character tries to move outside this bounding box you scroll the level to his movements. If you want absolute camera focus on your character, you can just scroll the level around your character. You will still need to keep track of the characters position on the screen and the offset scroll of the level. If you have both of those, you know where in the "level" your character is for collisions.

if this is not what you are looking for I am sorry, but it is a much simpler approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文