【问题标题】:Sprite Movement and Animation in XNAXNA 中的精灵运动和动画
【发布时间】:2014-01-27 04:50:51
【问题描述】:

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

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


    }
}

【问题讨论】:

  • 我有点害怕 MageChar 是一个动作而不是一个动作变量……不过你一定是在学习。

标签: c# animation xna sprite


【解决方案1】:

为了控制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) -> sqrt(32) = 5.65。要解决这个问题,再次到 4,您将需要 Normalize 这个变量。如果需要,我可以详细说明。


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

【讨论】:

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