动画帧未正确旋转
本文关键字:旋转 动画 | 更新日期: 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
当您的position
与mousePosition
相同时,XNA 不允许您Normalize
长度为 0 的Vector2
。所以试试这样的事情:
if (mousePosition != position)
{
distance = mousePosition - position;
distance.Normalize();
rotation = (float)Math.Atan2(distance.Y, distance.X);
}
这样,您的rotation
将保持不变 飞船到达mousePosition
之前 .