XNA中的Sprite移动和动画

时间:2014-01-08 21:13:09

标签: c# animation xna sprite

我正在制作和RPG,并为精灵编码了动作和动画。当我运行项目时,精灵将向下或向右移动。按下右箭头键时,精灵将向右移动,但不会停止。按下向下键时,精灵将向下移动,并在释放按键时停止。但是,按下向下或向右键后按另一个箭头键时,精灵图像不会改变方向。此外,按下新箭头键时,精灵图像不会改变。为什么会这样?任何帮助表示赞赏。

Game.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace RPG
{
    /// <summary>
    /// Default Project Template
    /// </summary>
    public class Game1 : Game
    {

        #region Fields

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Vector2 aPosition = new Vector2(250, 100);
        MageChar mageSprite;

        #endregion

        #region Initialization

        public Game1 ()
        {

            graphics = new GraphicsDeviceManager (this);

            Content.RootDirectory = "Content";

            graphics.IsFullScreen = false;
        }

        /// <summary>
        /// Overridden from the base Game.Initialize. Once the GraphicsDevice is setup,
        /// we'll use the viewport to initialize some values.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            mageSprite = new MageChar();
            base.Initialize();
        }

        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            mageSprite.LoadContent(this.Content);           
        }

        #endregion

        #region Update and Draw

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // game exits id back button is pressed
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            //calls update method of MageChar class
            mageSprite.Update(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself. 
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            spriteBatch.Begin();
            //calls draw method of MageChar class
            mageSprite.Draw(this.spriteBatch);
            spriteBatch.End();

            base.Draw(gameTime);
        }

        #endregion

    }
}

CharMovement.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace RPG
{
    public class CharMovement
    {
        //The asset name for the Sprite's Texture
        public string charSprite;
        //The Size of the Sprite (with scale applied)
        public Rectangle Size;
        //The amount to increase/decrease the size of the original sprite. 
        private float mScale = 1.0f;
        //The current position of the Sprite
        public Vector2 Position = new Vector2(0, 0);
        //The texture object used when drawing the sprite
        private Texture2D charTexture;


        //Load the texture for the sprite using the Content Pipeline
        public void LoadContent(ContentManager theContentManager, string theCharSprite)
        {
            //loads the image of the sprite
            charTexture = theContentManager.Load<Texture2D>(theCharSprite);

            theCharSprite = charSprite;

            //creates a new rectangle the size of the sprite
            Size = new Rectangle(0, 0, (int)(charTexture.Width * mScale), (int)(charTexture.Height * mScale));
        }

        //Update the Sprite and change it's position based on the set speed, direction and elapsed time.
        public void Update(GameTime theGameTime, Vector2 theSpeed, Vector2 theDirection)
        {
            //calculates the position of the sprite using the speed and direction from the MageChar class
            Position += theDirection * theSpeed * (float)theGameTime.ElapsedGameTime.TotalSeconds;
            if (Position.X < 0)
            {
                Position.X = 0;
            }
            if (Position.Y < 0)
            {
                Position.Y = 0;
            }
        }

        //Draw the sprite to the screen
        public void Draw(SpriteBatch theSpriteBatch)
        {
            //draw the sprite to the screen inside a rectangle     
            theSpriteBatch.Draw(charTexture, Position,
                new Rectangle(0, 0, charTexture.Width, charTexture.Height),
                Color.White, 0.0f, Vector2.Zero, mScale, SpriteEffects.None, 0);
        }
    }

}

MageChar.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace RPG
{
    public class MageChar : CharMovement
    {
        //variable where sprite file name is stored
        string MageAssetName = "WalkingFront";
        //starting x position
        const int StartPositionX = 0;
        //starting y position
        const int StartPositionY = 0;
        //speed that the sprite will move on screen
        const int MageSpeed = 160;
        //move sprite 1 up/down when the arrow key is pressed
        const int MoveUp = 1;
        const int MoveDown = 1;
        const int MoveLeft = 1;
        const int MoveRight = 1;

        //used to store the current state of the sprite
        enum State
        {
            WalkingLeft,
            WalkingRight,
            WalkingFront,
            WalkingBack
        }
        //set to current state of the sprite. initally set to walking
        State CurrentState = State.WalkingFront;

        //stores direction of sprite
        Vector2 Direction = Vector2.Zero;

        //stores speed of sprite
        Vector2 Speed = Vector2.Zero;

        //stores previous state of keyboard
        KeyboardState PreviousKeyboardState;

        public void LoadContent(ContentManager theContentManager)
        {
            //sets position to the top left corner of the screen
            Position = new Vector2(StartPositionX, StartPositionY);

            //calls the load content method of the CharMovement class, passing in the content manager, and the name of the sprite image
            base.LoadContent(theContentManager, MageAssetName);
        }

        //checks state of the keyboard
        private void Update(KeyboardState aCurrentKeyboardState)
        {

            //run if the sprite is walking
            if (CurrentState == State.WalkingFront)
            {
                //sets direction and speed to zero
                Speed = Vector2.Zero;
                Direction = Vector2.Zero;

                //if left key is pressed, move left
                if (aCurrentKeyboardState.IsKeyDown(Keys.Left) == true)
                {
                    CurrentState = State.WalkingLeft;
                    MageAssetName = "WalkingLeft";
                    //speed of sprite movement
                    Speed.X -= MageSpeed;
                    //moves the sprite left
                    Direction.X -= MoveLeft;
                }
                //if right key is pressed, move right
                else if (aCurrentKeyboardState.IsKeyDown(Keys.Right) == true)
                {
                    CurrentState = State.WalkingRight;
                    MageAssetName = "WalkingRight";
                    //speed of sprite movement
                    Speed.X += MageSpeed;
                    //moves the sprite right
                    Direction.X += MoveRight;
                }
                //if up key is pressed, move up
                if (aCurrentKeyboardState.IsKeyDown(Keys.Up) == true)
                {
                    CurrentState = State.WalkingBack;
                    MageAssetName = "WalkingBack";
                    //speed of sprite movement
                    Speed.Y += MageSpeed;
                    //moves sprite up
                    Direction.Y += MoveUp;
                }
                //if down key is pressed, move down
                else if (aCurrentKeyboardState.IsKeyDown(Keys.Down) == true)
                {
                    CurrentState = State.WalkingFront;
                    MageAssetName = "WalkingFront";
                    //speed of sprite movement
                    Speed.Y -= MageSpeed;
                    //moves sprite down
                    Direction.Y -= MoveDown;
                }

            }
        }

        public void Update(GameTime theGameTime)
        {
            //obtains current state of the keyboard
            KeyboardState aCurrentKeyboardState = Keyboard.GetState();

            //calls in UpdateMovement and passes in current keyboard state
            Update(aCurrentKeyboardState);

            //set previous state to current state
            PreviousKeyboardState = aCurrentKeyboardState;

            //call update method of the charMovement class, passing in the gametime, speed and direction of the sprite
            base.Update(theGameTime, Speed, Direction);
        }


    }
}

1 个答案:

答案 0 :(得分:0)

要控制LeftDown键,请减少Speed

Speed.X -= MageSpeed; // Keys.Left
Speed.Y -= MageSpeed; // Keys.Down

基于Speed的常规用法,这似乎不正确。例如,如果玩家向右移动并且速度为5.然后向左移动将取消此速度并将其设置为0.因此玩家不会移动。

所以在所有4个案例中,Speed都应该递增(+ =)。

Speed.X += MageSpeed; // Keys.Left
Speed.Y += MageSpeed; // Keys.Down

如果播放器没有按任何方向键,我建议使用else条件。在此,您可以将角色MageChar设置为继续朝向与上次移动方向相同的方向,并将Speed设置为0.

MageChar中移动的代码存在潜在问题:

根据用户输入,您将CurrentState设置为State.WalkingLeftState.WalkingRight。接下来检查向上和向下键。如果同时按下其中任何一个,则CurrentStateMageAssetName将被覆盖,如果它们已被分配到左/右代码块中。

这与你在问题中所述的内容一致:

按下向下键时,精灵将向下移动,并在释放该键时停止。但是,按下向下或向右键后按另一个箭头键时,精灵图像不会改变方向。此外,按下新箭头键时,精灵图像不会改变。

我建议先行动一下。我建议对每个移动方向/键执行独立检查。目前,如果玩家按下左键,则右键码完全被忽略,上下键分别相同。

当您递增和递减时,您的Direction值应该是正确的。然而,直观地说,按下左右两个,或者向上和向下按压都会取消彼此的移动。如果您同意,四个独立的运动检查将解决此问题。

当您修复此问题时,您可能需要考虑一些事情,我希望您这样做。在玩家沿对角线移动的情况下,将向上或向下以及向左或向右移动。在这里你可能会注意到玩家在对角线移动时移动得更快。这可以用毕达哥拉斯定理来解释* a ^ 2 + b ^ 2 = c ^ 2.

因此,如果玩家向右移动4,则向上移动4.结果速度为5.65。 (4 ^ 2 + 4 ^ 2 = 32) - &gt; sqrt(32)= 5.65。要解决此问题,再次使用4,您将需要Normalize此变量。如果需要,我可以详细介绍。


*毕达哥拉斯定理解释:Pythagaros Theorem Wikipedia Article

相关问题