3
\$\begingroup\$

Using a tutorial found on the AppHub, I've been attempted to add controls to a sample sprite sheet. I am able to get all the animations working, but for stuff like punching or stabbing, the animations require a timer to stop them from playing repeatedly. XNA uses a default framerate of 60, but I have the animations running at 10 FPS using the following code:

int punchIndex = walk.GetIndex("obj_Walk000");

punchIndex += (int)(time * animationFPS) % punchFC;
batch.Draw(punch.Texture, position, punch.SourceRectangle(punchIndex), Color.White, rotation, origin, 1.0f, SpriteEffects.FlipHorizontally, 1.0f);
break;

Where animationFPS = 10 and punchFC is 6, which is the number of frames in the animation. Using this data, I have calculated a required time of 0.5 seconds for the animation to complete, but that seems to be incorrect, so I'm looking for someone to show me how to do the math properly.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I don't think XNA uses a fixed FPS. I thought it uses a variable FPS that depends on your CPU and stuff. \$\endgroup\$
    – ashes999
    Commented Mar 5, 2012 at 4:31
  • 1
    \$\begingroup\$ @ashes999 There's a property to toggle between fixed time step and variable time step in XNA. When running in fixed time step, if performance starts suffering and it can't keep up with the specified time step, you're warned through another property. \$\endgroup\$ Commented Mar 5, 2012 at 4:34

1 Answer 1

5
\$\begingroup\$

First of all I recommend separating it so that the frame is updated in the Update method instead of the Draw method. That's because XNA is free to skip a few Draw calls to make up for lost time when the game runs slowly, but not Update, so it should run more consistently.

It's also a better idea to leave the Draw method just for rendering, and putting any state changes in the Update method of your classes.

Now for your problem, here's the basic structure of how to enforce an animation framerate indepdentent of the game's framerate (in this example 10 FPS):

private float _timer = 0.0f;
private float _framerate = 10f;
private int _currentFrame = 0;
private int _frameCount = 6;
private bool _animating = true;

public void Update(GameTime gameTime)
{
    if(!_animating) return;

    _timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

    if (_timer >= 1.0f / _framerate)
    {
        _timer -= 1.0f / _framerate;
        _currentFrame = (_currentFrame + 1) % _frameCount;

        if(_currentFrame == 0) 
        {
            _animating = false;
            _timer = 0f;
        }
    }
}

public void Draw(GameTime gameTime)
{
    // Draw _currentFrame
}

Of course you can precalculate and store 1.0f / _framerate to avoid having to recompute it every frame.

\$\endgroup\$
4
  • \$\begingroup\$ Enforcing the framerate has not been the issue. I'm trying to stop an animation after all of its frames have been drawn once. That is good to know that XNA can skip Draw calls though - I will move that logic. \$\endgroup\$
    – 131nary
    Commented Mar 5, 2012 at 4:46
  • \$\begingroup\$ @131nary Okay I edited it once more and consolidated all the checks in the same example this time. \$\endgroup\$ Commented Mar 5, 2012 at 4:54
  • \$\begingroup\$ Ah ok. Instead of having a set time, you simply check if you've cycled through. That's a more elegant solution. \$\endgroup\$
    – 131nary
    Commented Mar 5, 2012 at 4:56
  • \$\begingroup\$ @131nary Exactly, and simpler too. Of course there's room for variation. You might for instance prefer to stop the animation at the final frame instead of waiting for it to loop back to the start, but you get the idea. Either way, it's easier to just handle this when the frame changes, instead of messing with time. \$\endgroup\$ Commented Mar 5, 2012 at 4:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .