简体   繁体   English

动画帧率与游戏fps

[英]Animation frame rate vs game fps

I'm a beginner programmer just starting out with MonoGame. 我是一个刚开始使用MonoGame的初学者。 I was implementing some code for running an animation and came to a problem I don't know how to solve. 我实现了一些用于运行动画的代码,但遇到了一个我不知道如何解决的问题。 This is the code I used in my AnimationManager class: 这是我在AnimationManager类中使用的代码:

public void Update(GameTime gameTime)
{
    timeElapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;

    if (timeElapsed > timeToUpdate)
    {
        timeElapsed -= timeToUpdate;
        //Tried to just reset timeElapsed to zero, still doesn't work
        //timeElapsed = 0;
        if (frameIndex < rectangles.Count -1)
        {
            frameIndex++;
        }
        else if (isLooping)
        {
            frameIndex = 0;
        }
    }
}

The problem is I animate at 24 frames per second and when the game runs at 60 or 30 fps and on each update code checks is it time to draw a new frame of animation, you get some remainder of frames, because you tried to draw 24 images per second, evenly, with 30 even game frames per second. 问题是我以每秒24帧的速度进行动画处理,并且当游戏以60或30 fps的速度运行并且每次更新代码检查是时候绘制新的动画帧时,您还是会得到一些剩余的帧,因为您尝试绘制24每秒平均30张游戏画面。 So there's that remainder of 6 frames. 因此,剩下的还有6帧。 The result of this is that approx 6 frames of animation gets drawn twice, some are skipped a whole animation gets about 25% longer. 这样的结果是大约两次绘制了6帧动画,有些动画被跳过了,整个动画的时间延长了约25%。 Is there a way to fix this? 有没有办法解决这个问题? Can I maybe move this code to Draw call and then cap just the draw calls at 48 fps for 60 fps game, so each animation frame will be drawn at every second draw call. 我是否可以将这段代码移到Draw调用,然后将60 fps游戏的Draw调用限制为48 fps,所以每个动画帧将在第二次绘制调用时绘制。 I don't know how would I go about doing this if it's a reasonable solution at all? 如果完全是一个合理的解决方案,我不知道该怎么做?

And how will VSync affect all of this at the end. 最后,VSync将如何影响所有这些。 Will it mess up animation frames, even if this problem is solved. 即使解决了此问题,它也会使动画帧混乱吗?

EDIT: forgot to say it's a 2d game, hand drawn animation. 编辑:忘了说这是一个2D游戏,手绘动画。

Generally when you're doing this kind of stuff you don't need to worry about VSync or the fact that your game runs at 60 or 30 fps. 通常,当您执行此类操作时,无需担心VSync或游戏以60或30 fps运行的事实。 That's all pretty much irrelevant. 这几乎是无关紧要的。

The thing that matters is that you know the desired frames per second of your animation and how long it takes for a single game frame. 重要的是,您知道动画每秒所需的帧数,以及单个游戏帧需要多长时间。

From that you can calculate the length of time in a single animation frame . 由此,您可以计算单个动画帧中的时间长度。 For example, you'd end up with something like this: 例如,您最终将得到如下结果:

var animationFrameTime = 1f / 24f;   // 24 frames per second

So far so good. 到现在为止还挺好。

The next thing you need to do is to start accumulating time somewhere. 接下来需要做的是开始在某个地方累积时间。 There's a few different ways to think about this. 有几种不同的方式来考虑这一点。 I like to think about it in terms of how much time is left until the next frame . 我喜欢考虑到下一帧还有多少时间

var gameFrameTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
timeUntilNextFrame -= gameFrameTime;

Then you need to increment the frameIndex when you've run out of frame time. 然后,当帧时间用完时,需要增加frameIndex

if(timeUntilNextFrame <= 0)
{
    frameIndex++;
    timeUntilNextFrame += animationFrameTime;
}

Notice the important bit here. 注意这里的重要部分。 I've added the animationFrameTime to the timeUntilNextFrame . 我已经 animationFrameTime 添加timeUntilNextFrame This way, if there's any left over time from the previous frame, it'll get added to the next frame, keeping the animation smooth. 这样,如果上一帧还有剩余时间,它将被添加到下一帧,以保持动画流畅。

There's really not much more to it than that. 确实,除了这些之外,还没有其他更多的东西。 I've left out the rectangles.Count and isLooping bits, but it should be easy enough to add those back in. You might also want to initialize timeUntilNextFrame to animationFrameTime for the first frame. isLooping去了rectangles.CountisLooping位,但是添加它们应该很容易。您可能还想将timeUntilNextFrame初始化为第一帧的animationFrameTime

Just a word of warning with this code, if the game is running slowly for some reason (or perhaps it's paused maybe) the gameFrameTime might end up having a very large value causing some strange behavior. 只需对此代码警告一下,如果游戏由于某种原因(或可能已暂停)而缓慢运行,则gameFrameTime可能最终具有非常大的值,从而导致某些奇怪的行为。 I'm not entirely certain if that can ever happen in MonoGame / XNA but it's worth considering at least. 我不确定在MonoGame / XNA中是否能够做到这一点,但至少值得考虑。

It turned out this is a well known problem. 原来,这是一个众所周知的问题。 Basicaly its mathematicaly imposible to jam 24 animation fps in 30 game fps because they are not independent from each other. 基本上,从数学上讲不可能将24个动画fps限制在30个游戏fps中,因为它们彼此之间并不独立。 Interpolation is the only way to fix this problem. 插值是解决此问题的唯一方法。 It's the same thing that's being done whenever you watch 24 fps movie on a 60 hz monitor. 每当您在60 Hz的显示器上观看24 fps电影时,所做的事情都是一样的。

https://en.wikipedia.org/wiki/Three-two_pull_down https://zh.wikipedia.org/wiki/Three-two_pull_down

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM