我一直在研究这个问题很长一段时间在各个地方寻找解决方案。我已经使用了Nick Gravelyn将动画存储到文本文件中的方式,并且只是递增索引来更改帧。我遇到的麻烦是循环动画只有一次,但由于某种原因,我知道应该工作的方式并不像我想象的那样工作。我不能为我的生活找出原因,除非它对XNA的工作方式非常具体。
这是我的代码:
private void UpdateAttack(KeyboardState current, KeyboardState last, GameTime gameTime)
{
if (current.IsKeyDown(Keys.S) && last.IsKeyUp(Keys.S))
{
neutralStandingKick(gameTime);
}
}
private void neutralStandingKick(GameTime gameTime)
{
//timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; //Framerate control
//if (timeSinceLastFrame > millisecondsPerFrame) //Framerate control
//{
//timeSinceLastFrame -= millisecondsPerFrame; //Framerate control
if (mCurrentState != State.Kicking)
{
mCurrentState = State.Kicking;
Position.Y = 200;
loopOnce(25, 30); //Starts at frame 25, ends at 30
}
//}
}
private void loopOnce(int min, int max)
{
if (currentImageIndex > max || currentImageIndex < min) //Checks to see if index out of range of current animation
currentImageIndex = min; //Starts at the beginning of the animation
for (int i = min; i < max; i++) //Uses the range to determine when to stop
{ currentImageIndex++; } //Increments index each iteration that passes
}
编辑:这是此特定类的Draw方法
public void Draw(SpriteBatch spriteBatch)
{
//Get the name of the current sprite to draw
string spriteName = possibleImages[currentImageIndex];
//Use that to get the source rectangle
Rectangle source = spriteSourceRectangles[spriteName];
//Send rectangle to a function to set the framesize for bounds checking
getFrameSize(source);
spriteBatch.Draw(theSpriteSheet, Position, source, Color.White);
}
private void getFrameSize(Rectangle frame)
{
frameSize = frame; //For bounds checking
}
为什么这不起作用?
新规范(Gavin的建议):
private void UpdateAttack(KeyboardState current, KeyboardState last, GameTime gameTime)
{
const int min = 22;
const int max = 30;
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; //Framerate control
if (current.IsKeyDown(Keys.S) && mCurrentState != State.Kicking)
{
mCurrentState = State.Kicking;
currentImageIndex = min;
}
if (mCurrentState == State.Kicking)
{
if (timeSinceLastFrame > millisecondsPerFrame) //Framerate control
{
timeSinceLastFrame -= millisecondsPerFrame; //Framerate control
currentImageIndex++;
}
}
if (currentImageIndex == max)
mCurrentState = State.Idle;
}
调用UpdateAttack的方法:
public void Update(GameTime theGameTime, Game game)
{
KeyboardState aCurrentKeyboardState = Keyboard.GetState();
UpdateMovement(aCurrentKeyboardState);
UpdateJump(aCurrentKeyboardState);
UpdateAttack(aCurrentKeyboardState, mPreviousKeyboardState, theGameTime);
UpdateStageBounds(game);
mPreviousKeyboardState = aCurrentKeyboardState;
}
它会在按住键盘键“s”时循环播放动画。但它不会像它应该的那样在1个按键中循环所有7个帧。
答案 0 :(得分:0)
从我所看到的,您发布的代码将只绘制踢动画的最后一帧,因为LoopOnce方法中的for循环遍历所有帧并且仅绘制最后一帧。这是因为每次更新都会调用一次draw方法。
XNA在调用draw之后首先调用update方法。因此,在您的更新方法中,您将动画的当前帧设置为最大帧,然后进入绘制方法,然后绘制当前帧,此时此帧是最后一帧。
为了使其正常工作,您只需要为每次更新调用将要绘制的帧增加一个。
我在这台计算机上没有XNA,所以我无法测试这个并且它可能在没有修复任何语法错误的情况下编译但是为了让你知道这样的事情应该这样做
private void UpdateAttack(KeyboardState current, KeyboardState last, GameTime gameTime)
{
if (current.IsKeyDown(Keys.S) && last.IsKeyUp(Keys.S))
{
mCurrentState =State.Kicking;
currentImageIndex=25;
}
if(mCurrentState ==State.Kicking)
neutralStandingKick(gameTime);
}
private void neutralStandingKick(GameTime gameTime)
{
currentImageIndex++;
if(currentImageIndex==30) mCurrentStart = State.SomeOtherState;
}
删除一次绘制方法。当对象没有踢时,你需要将State.SomeOtherState替换为其中的状态。您可能还希望将硬编码帧编号与常量交换。无需更改此绘制方法即可使此动画生效。希望这会有所帮助。