![](/img/trans.png)
[英]Why does one SpriteBatch.Draw causes frame rate to drop 23 fps?
[英]Animation frame rate vs game fps
我是一个刚开始使用MonoGame的初学者。 我实现了一些用于运行动画的代码,但遇到了一个我不知道如何解决的问题。 这是我在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;
}
}
}
问题是我以每秒24帧的速度进行动画处理,并且当游戏以60或30 fps的速度运行并且每次更新代码检查是时候绘制新的动画帧时,您还是会得到一些剩余的帧,因为您尝试绘制24每秒平均30张游戏画面。 因此,剩下的还有6帧。 这样的结果是大约两次绘制了6帧动画,有些动画被跳过了,整个动画的时间延长了约25%。 有没有办法解决这个问题? 我是否可以将这段代码移到Draw调用,然后将60 fps游戏的Draw调用限制为48 fps,所以每个动画帧将在第二次绘制调用时绘制。 如果完全是一个合理的解决方案,我不知道该怎么做?
最后,VSync将如何影响所有这些。 即使解决了此问题,它也会使动画帧混乱吗?
编辑:忘了说这是一个2D游戏,手绘动画。
通常,当您执行此类操作时,无需担心VSync或游戏以60或30 fps运行的事实。 这几乎是无关紧要的。
重要的是,您知道动画每秒所需的帧数,以及单个游戏帧需要多长时间。
由此,您可以计算单个动画帧中的时间长度。 例如,您最终将得到如下结果:
var animationFrameTime = 1f / 24f; // 24 frames per second
到现在为止还挺好。
接下来需要做的是开始在某个地方累积时间。 有几种不同的方式来考虑这一点。 我喜欢考虑到下一帧还有多少时间 。
var gameFrameTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
timeUntilNextFrame -= gameFrameTime;
然后,当帧时间用完时,需要增加frameIndex
。
if(timeUntilNextFrame <= 0)
{
frameIndex++;
timeUntilNextFrame += animationFrameTime;
}
注意这里的重要部分。 我已经将 animationFrameTime
添加到timeUntilNextFrame
。 这样,如果上一帧还有剩余时间,它将被添加到下一帧,以保持动画流畅。
确实,除了这些之外,还没有其他更多的东西。 isLooping
去了rectangles.Count
和isLooping
位,但是添加它们应该很容易。您可能还想将timeUntilNextFrame
初始化为第一帧的animationFrameTime
。
只需对此代码警告一下,如果游戏由于某种原因(或可能已暂停)而缓慢运行,则gameFrameTime
可能最终具有非常大的值,从而导致某些奇怪的行为。 我不确定在MonoGame / XNA中是否能够做到这一点,但至少值得考虑。
原来,这是一个众所周知的问题。 基本上,从数学上讲不可能将24个动画fps限制在30个游戏fps中,因为它们彼此之间并不独立。 插值是解决此问题的唯一方法。 每当您在60 Hz的显示器上观看24 fps电影时,所做的事情都是一样的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.