动画帧未正确旋转

本文关键字:旋转 动画 | 更新日期: 2023-09-27 18:35:33

所以当我的飞船只是一个纹理时,我会点击屏幕,飞船会面对那个点击点并慢慢向它移动,只有在纹理的中间到达所述点(我想要的)时才停下来。所以现在我尝试为它制作动画。动画工作正常,但现在飞船不会朝向我点击的位置的方向,它面向左或右几度,飞船行驶到那个点,但当它停下来时,它永远不会像它只是一个纹理时那样在确切的点, 相反,它总是在离它更远的地方停下来。

我的动画课

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace AsteroidAvoider
{
    class Animation
    {
        float rotation;
        // The image representing the collection of images used for animation
        Texture2D spriteStrip;
        // The scale used to display the sprite strip
        float scale;
        // The time since we last updated the frame
        int elapsedTime;
        // The time we display a frame until the next one
        int frameTime;
        // The number of frames that the animation contains
        int frameCount;
        // The index of the current frame we are displaying
        int currentFrame;
        // The color of the frame we will be displaying
        Color color;
        // The area of the image strip we want to display
        Rectangle sourceRect = new Rectangle();
        // The area where we want to display the image strip in the game
        Rectangle destinationRect = new Rectangle();
        // Width of a given frame
        public int FrameWidth;
        // Height of a given frame
        public int FrameHeight;
        // The state of the Animation
        public bool Active;
        // Determines if the animation will keep playing or deactivate after one run
        public bool Looping;
        public Vector2 Position;
        public void Initialize(Texture2D texture, Vector2 position, int frameWidth, int frameHeight, int frameCount, int frametime, Color color, float scale, bool looping)
        {
            // Keep a local copy of the values passed in
            this.color = color;
            this.FrameWidth = frameWidth;
            this.FrameHeight = frameHeight;
            this.frameCount = frameCount;
            this.frameTime = frametime;
            this.scale = scale;
            Looping = looping;
            Position = position;
            spriteStrip = texture;
            // Set the time to zero
            elapsedTime = 0;
            currentFrame = 0;
            // Set the Animation to active by default
            Active = true;
        }
        public void Update(GameTime gameTime)
        {
            // Do not update the game if we are not active
            if (Active == false)
                return;
            // Update the elapsed time
            elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
            // If the elapsed time is larger than the frame time
            // we need to switch frames
            if (elapsedTime > frameTime)
            {
                // Move to the next frame
                currentFrame++;
                // If the currentFrame is equal to frameCount reset currentFrame to zero
                if (currentFrame == frameCount)
                {
                    currentFrame = 0;
                    // If we are not looping deactivate the animation
                    if (Looping == false)
                        Active = false;
                }
                // Reset the elapsed time to zero
                elapsedTime = 0;
            }
            // Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
            sourceRect = new Rectangle(currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);
            // Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
            destinationRect = new Rectangle((int)Position.X - (int)(FrameWidth * scale) / 2,
            (int)Position.Y - (int)(FrameHeight * scale) / 2,
            (int)(FrameWidth * scale),
            (int)(FrameHeight * scale));
        }
        // Draw the Animation Strip
        public void Draw(SpriteBatch spriteBatch, float rotation)
        {
            this.rotation = rotation;
            // Only draw the animation when we are active
            if (Active)
            {
                //spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color);
                spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color, rotation, new Vector2(100, 75), SpriteEffects.None, 1);
            }
        }
    }
}

我的玩家类

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 AsteroidAvoider
{
    class Player
    {
        public Vector2 position, distance, mousePosition;
        public float speed;
        public float rotation;
        public MouseState mouseState;
        public bool canMove = false;
        Animation playerAnimation;
        public Player(Animation playerAnimation, Vector2 position, float speed)
        {
            this.playerAnimation = playerAnimation;
            this.position = position;
            this.speed = speed;
            playerAnimation = new Animation();
        }
        public void Update(GameTime gameTime)
        {
            mouseState = Mouse.GetState();
            float speedForThisFrame = speed;
            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                mousePosition.X = mouseState.X;
                mousePosition.Y = mouseState.Y;
            }
            if ((mousePosition - position).Length() < speed)
                speedForThisFrame = 0;
            if ((mousePosition - position).Length() > speed)
                speedForThisFrame = 2.0f;
            distance = mousePosition - position;
            distance.Normalize();
            rotation = (float)Math.Atan2(distance.Y, distance.X);
            //position += distance * speedForThisFrame;
            if (speedForThisFrame == 0)
                position = mousePosition;
            else
                position += distance * speedForThisFrame;
            playerAnimation.Position = position;
            playerAnimation.Update(gameTime);
        }
        public void Draw(SpriteBatch spriteBatch)
        {
            playerAnimation.Draw(spriteBatch, rotation);
        }
    }
}

我的游戏1类

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 AsteroidAvoider
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Player player;
        Texture2D playerImage;
        Animation playerAnimation;
        Vector2 playerPosition = new Vector2(550, 550);
        float playerSpeed = 2f;
        ParallaxingBackground bg;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = 1500;
            graphics.PreferredBackBufferHeight = 600;
        }
        protected override void Initialize()
        {
            Animation playerAnimation = new Animation();
            playerImage = Content.Load<Texture2D>("player");
            player = new Player(playerAnimation, playerPosition, playerSpeed);
            playerAnimation.Initialize(playerImage, playerPosition, 200, 150, 4, 30, Color.White, 1f, true);
            this.IsMouseVisible = true;
            bg = new ParallaxingBackground();
            bg.Initialize(Content, "background", GraphicsDevice.Viewport.Width, -1);
            base.Initialize();
        }
        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
        }
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            // TODO: Add your update logic here
            player.Update(gameTime);
            bg.Update();
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();
            // TODO: Add your drawing code here
            bg.Draw(spriteBatch);
            player.Draw(spriteBatch);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

动画帧未正确旋转

如果你的宇宙飞船朝向左或右几度,我认为这意味着你的spriteBatch.Draw sourceRectangle参数不正确。

对于你的第二个问题,当宇宙飞船停止时,它永远不会在确切的点,你必须在它靠近mousePosition时手动设置它的位置,因为设置speedForThisFrame = 0不能确保它处于正确的位置,你仍然有(mousePosition - position).Length()的不确定性。

编辑

我的意思是这样的:

if (speedForThisFrame == 0)
  position = mousePosition;
else
  position += distance * speedForThisFrame;

假设position位于宇宙飞船精灵的船头或任何您需要的地方。

编辑 2

当您的positionmousePosition相同时,XNA 不允许您Normalize长度为 0 的Vector2。所以试试这样的事情:

if (mousePosition != position)
{
   distance = mousePosition - position;
   distance.Normalize();
   rotation = (float)Math.Atan2(distance.Y, distance.X);
}

这样,您的rotation将保持不变 飞船到达mousePosition之前 .