我正在使用 XNA构建我的第一个游戏并且我正在尝试让我的精灵运行。 第一个精灵的一切都很好。 例如:如果我向右走(D)我的精灵看起来是正确的,如果我向左走(A)我的精灵向左看,如果我没有触摸任何东西,我的精灵是默认的精灵。 现在我要做的是如果精灵变为右,我想要改变精灵(左腿,右腿,左腿等......) xCurrent 是当前精灵绘制的 xRunRight < / em>是第一个正在运行的Sprite,而 xRunRight1 是在运行时必须与 xRunRight 交换的那个。 这就是我现在所拥有的:
protected override void Update(GameTime gameTime)
{
float timer = 0f;
float interval = 50f;
bool frame1 = false ;
bool frame2 = false;
bool running = false;
KeyboardState FaKeyboard = Keyboard.GetState();
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if ((FaKeyboard.IsKeyUp(Keys.A)) || (FaKeyboard.IsKeyUp(Keys.D)))
{
xCurrent = xDefault;
}
if (FaKeyboard.IsKeyDown(Keys.D))
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
if (timer > interval)
{
if (frame1)
{
xCurrent = xRunRight;
frame1 = false;
}
else
{
xCurrent = xRunRight1;
frame1 = true;
}
}
xPosition += xDeplacement;
}
任何想法......?我已经坚持了一段时间.. 提前致谢,如果您需要代码中的任何其他部分,请告知我们。
答案 0 :(得分:2)
您忘记重置计时器,您可以在达到timer interval
条件时执行此操作。此外,50ms似乎对于一个间隔来说有点太小,也许你可以做到400ms?
除此之外,看起来不错,它会做你想要的。
或者,你可以考虑制作动画精灵来行走。你做的是使用相同大小的步行动画精灵制作一个图像。您只绘制此图像的一部分(一个精灵)并根据时间移动它们。
以下是可能是动画纹理的快速代码:
class AnimatedTexture2D : Texture2D
{
int _numberOfImages;
int _currentImage = 0;
int _timeInterval;
int _spriteWidth;
public Rectangle DrawFromRectangle
{
get
{
return new Rectangle(_currentImage * _spriteWidth, 0, _spriteWidth, this.Height);
}
}
public AnimatedTexture2D(Texture2D entireImage, int spriteWidth, int numberOfImages, int timeInterval)
: base(entireImage.GraphicsDevice, entireImage.Width, entireImage.Height)
{
_numberOfImages = numberOfImages;
_timeInterval = timeInterval;
_spriteWidth = spriteWidth;
Color[] data = new Color[entireImage.Width * entireImage.Height];
entireImage.GetData<Color>(0, new Rectangle(0, 0, entireImage.Width, entireImage.Height), data, 0, entireImage.Width * entireImage.Height);
this.SetData<Color>(data);
}
public void Animate(GameTime gameTime)
{
int totalImageTime = _timeInterval * _numberOfImages;
int currentPoint = (int)gameTime.TotalGameTime.TotalMilliseconds % totalImageTime;
_currentImage = currentPoint / _timeInterval;
}
}
用法非常简单:
1)在某处声明:
AnimatedTexture2D animatedTexture;
2)用你的纹理启动它(我有一个2560x64的40个64 * 64图像序列),其中各个图像水平放置在彼此旁边:
animatedTexture = new AnimatedTexture2D(Content.Load<Texture2D>(@"Textures\Loading"), 64, 40, 20);
3)在Update()方法中,调用:
animatedTexture.Animate(gameTime);
4)在你的Draw()方法中,调用:
SpriteBatch.Draw(animatedTexture, new Rectangle(20, 20, 64, 64), animatedTexture.DrawFromRectangle, Color.White);
不要忘记第4部分中的DrawFromRectangle! (注意目标矩形使用声明的单个部分宽度,而不是我的测试中2560像素的整个纹理宽度)
现在,在您的代码中,您可以忘记间隔部分和游戏时间部分,您可以使用它而不是默认部分!
另外,如果您不喜欢我的计时代码(它非常简单但缺乏重置动画的方法),请更改它以便您有一个已用时间变量,并像在您自己的代码中一样添加它,并且用它来改变_currentImage。您甚至可以将该变量公开,以便您可以使用它来重置动画(或将其设置为指定点)。
当然,您也可以将默认值设为仅包含一个帧的动画纹理,这样您就可以在任何地方使用相同的代码。希望这有帮助!
答案 1 :(得分:1)
你需要保持最后一次调用Update(..),间隔应该是...... well ..一个间隔,即ElapsedGameTime和最后一次调用更新ElapsedGameTime之间的差异。 使用您班级的新成员(LastElapsedGameTimeUpdateCalled)或您的潜水员的静态成员。
答案 2 :(得分:1)
如果您知道每个动画将具有相同数量的帧,则每个sprite可以保留3个变量(在类中封装以获得最佳结果)。 BaseFrame是一个用于保存全局动画编号的整数。 SubFrame是动画的偏移量,用于保存当前所在的帧。 FrameAccumulator保存时序信息。
每次调用更新时,将自上次更新以来的ms数添加到累加器。一旦累加器超过动画定时,增加SubFrame,并重置累加器。检查subFrame是否大于每个动画的帧数,如果是,则将其设置回0.您可以通过添加BaseFrame + Subframe从中获取实际帧索引。当您需要显示不同的动画时,只需更改BaseFrame。
让我们说每个动画有3帧,你有2个动画。你总共有6个帧。 RunLeft将是BaseFrame 0,RunRight将是BaseFrame 3.这应该很容易给你绘制的帧号。