我关注:http://xbox.create.msdn.com/en-US/education/tutorial/2dgame/animating_the_player并且在实施动画期间出现了问题。但我不确定原因:
Game1.cs(我在这里更改的唯一方法是LoadContent() - 方法和UpdatePlayer() - 方法。
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;
using Microsoft.Xna.Framework.Input.Touch;
namespace Shooter
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Represents the player
Player player;
KeyboardState currentKeyboardState;
KeyboardState previousKeyboardState;
GamePadState currentGamePadState;
GamePadState previousGamePadState;
float playerMoveSpeed;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
player = new Player();
playerMoveSpeed = 8.0f;
TouchPanel.EnabledGestures = GestureType.FreeDrag;
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your 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
//Load the player resources
// Load the player resources
Animation playerAnimation = new Animation();
Texture2D playerTexture = Content.Load<Texture2D>("shipAnimation");
playerAnimation.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);
Vector2 playerPosition = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y
+ GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
player.Initialize(playerAnimation, playerPosition);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <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)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
previousGamePadState = currentGamePadState;
previousKeyboardState = currentKeyboardState;
currentKeyboardState = Keyboard.GetState();
currentGamePadState = GamePad.GetState(PlayerIndex.One);
UpdatePlayer(gameTime);
base.Update(gameTime);
}
private void UpdatePlayer(GameTime gameTime)
{
player.Update(gameTime);
player.Position.X += currentGamePadState.ThumbSticks.Left.X *playerMoveSpeed;
player.Position.Y -= currentGamePadState.ThumbSticks.Left.Y *playerMoveSpeed;
if (currentKeyboardState.IsKeyDown(Keys.Left) || currentGamePadState.DPad.Left == ButtonState.Pressed)
{
player.Position.X -= playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Right) || currentGamePadState.DPad.Right == ButtonState.Pressed)
{
player.Position.X += playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Up) || currentGamePadState.DPad.Up == ButtonState.Pressed)
{
player.Position.Y -= playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Down) || currentGamePadState.DPad.Down == ButtonState.Pressed)
{
player.Position.Y += playerMoveSpeed;
}
//Make sure the player does not go out of bounds
player.Position.X = MathHelper.Clamp(player.Position.X, 0, GraphicsDevice.Viewport.Width - player.Width);
player.Position.Y = MathHelper.Clamp(player.Position.Y, 0, GraphicsDevice.Viewport.Height - player.Height);
}
/// <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)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Player.cs
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Shooter
{
class Player
{
//Animation representing the player
public Animation PlayerAnimation;
//Position of the Player relative to the upper left side of the screen
public Vector2 Position;
//State of the player
public bool Active;
//Amount of hit points that player has
public int Health;
//Get the width of the player ship
public int Width
{
get { return PlayerAnimation.FrameWidth; }
}
//Get the height of the player ship
public int Height
{
get { return PlayerAnimation.FrameHeight; }
}
public void Initialize(Animation animation, Vector2 position)
{
PlayerAnimation = animation;
//Set the starting position of the player around the middle of the screen and to the back
Position = position;
//Set the player to be active
Active = true;
//Set the player health
Health = 100;
}
public void Update(GameTime gameTime)
{
PlayerAnimation.Position = Position;
PlayerAnimation.Update(gameTime);
}
public void Draw(SpriteBatch spriteBatch)
{
PlayerAnimation.Draw(spriteBatch);
}
}
}
Animation.cs
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Shooter
{
class Animation
{
// 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;
// Width of a given frame
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));
}
public void Draw(SpriteBatch spriteBatch)
{
if (Active)
{
spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color);
}
}
}
}
在Game1.cs中,这是检查边界的原因。但是,这部分教程没有改变,所以我不确定为什么它会开始发生,我错过了什么?你们有什么可以指出我做错了吗?
//Make sure the player does not go out of bounds
player.Position.X = MathHelper.Clamp(player.Position.X, 0, GraphicsDevice.Viewport.Width - player.Width);
player.Position.Y = MathHelper.Clamp(player.Position.Y, 0, GraphicsDevice.Viewport.Height - player.Height);
答案 0 :(得分:1)
在查看代码之后,我最好的猜测是问题在于动画的绘制功能以及destinationRect
的定义方式。
看起来游戏认为动画的中心是动画的左上角..
我想也许你想在动画的Update方法中设置destinationRect
,如此
// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
destinationRect = new Rectangle(
(int)Position.X,
(int)Position.Y,
(int)(FrameWidth * scale),
(int)(FrameHeight * scale));
矩形的X
和Y
坐标是动画的左上角而不是中心。