开发者

XNA 2D Camera - How to lock/center it to an animated sprite?

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
        {
            Lef开发者_开发知识库t,
            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);
            }
        }
    }
}


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜