XNA 2D Camera - Как заблокировать / центрировать его на анимированном спрайте? - PullRequest
2 голосов
/ 12 января 2011

Эй, я пытаюсь заставить мою камеру следовать моему спрайту, и по какой-то причине спрайт всегда движется быстрее, чем моя камера, и моя камера не может прижаться к экрану.Я хотел бы сделать так, чтобы камера постоянно центрировалась на спрайте и следовала за ним, когда он двигался.

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

Ответы [ 2 ]

6 голосов
/ 12 января 2011

Ваша камера должна сгенерировать матрицу представления для метода 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);
0 голосов
/ 12 января 2011

Здесь может быть более простое решение того, что вы пытаетесь сделать.

Поместите своего персонажа на экран внутри невидимой рамки. Всякий раз, когда персонаж пытается выйти за пределы этой ограничительной рамки, вы прокручиваете уровень до его движений. Если вам нужен абсолютный фокус камеры на персонаже, вы можете просто прокрутить уровень вокруг персонажа. Вам все равно нужно будет отслеживать положение символов на экране и прокрутку смещения уровня. Если у вас есть оба из них, вы знаете, где на «уровне» ваш персонаж для столкновений.

если это не то, что вы ищете, извините, но это гораздо более простой подход.

...