我正在尝试获取我游戏的当前FPS,但是我只能找到每秒更新FPS变量的方法。例如。 https://github.com/CartBlanche/MonoGame-Samples/blob/master/Draw2D/FPSCounterComponent.cs和http://www.david-amador.com/2009/11/how-to-do-a-xna-fps-counter/
有没有办法持续更新FPS标签?
答案 0 :(得分:26)
这是我刚才写的FPS计数器课程。您应该可以将它放在代码中并按原样使用它。
public class FrameCounter
{
public FrameCounter()
{
}
public long TotalFrames { get; private set; }
public float TotalSeconds { get; private set; }
public float AverageFramesPerSecond { get; private set; }
public float CurrentFramesPerSecond { get; private set; }
public const int MAXIMUM_SAMPLES = 100;
private Queue<float> _sampleBuffer = new Queue<float>();
public override bool Update(float deltaTime)
{
CurrentFramesPerSecond = 1.0f / deltaTime;
_sampleBuffer.Enqueue(CurrentFramesPerSecond);
if (_sampleBuffer.Count > MAXIMUM_SAMPLES)
{
_sampleBuffer.Dequeue();
AverageFramesPerSecond = _sampleBuffer.Average(i => i);
}
else
{
AverageFramesPerSecond = CurrentFramesPerSecond;
}
TotalFrames++;
TotalSeconds += deltaTime;
return true;
}
}
您需要做的就是在主Game类中创建一个成员变量..
private FrameCounter _frameCounter = new FrameCounter();
然后在Game的Draw方法中调用Update方法并绘制标签,但是你喜欢..
protected override void Draw(GameTime gameTime)
{
var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
_frameCounter.Update(deltaTime);
var fps = string.Format("FPS: {0}", _frameCounter.AverageFramesPerSecond);
_spriteBatch.DrawString(_spriteFont, fps, new Vector2(1, 1), Color.Black);
// other draw code here
}
享受! :)
答案 1 :(得分:5)
您可以使用以下公式在任何给定时刻获取当前帧速率:
framerate = (1 / gameTime.ElapsedGameTime.TotalSeconds);
下面介绍的其他两种方法都会为您提供修改后的帧速率,使其更平滑,并且返回值的波动更少
这个通过在对数刻度上加权所有先前的帧时间来工作。我不喜欢使用平均值来获得游戏性能的指标,因为framedrops没有表现得很好(或者如果你有很高的平均值),非常低/非常高的帧率有很大的不同如果它们以相同的平均值运行,则准确度如何。
为了解决这个问题,我制作了一个SmartFramerate类(可怕的名字,我知道)
class SmartFramerate
{
double currentFrametimes;
double weight;
int numerator;
public double framerate
{
get
{
return (numerator / currentFrametimes);
}
}
public SmartFramerate(int oldFrameWeight)
{
numerator = oldFrameWeight;
weight = (double)oldFrameWeight / ((double)oldFrameWeight - 1d);
}
public void Update(double timeSinceLastFrame)
{
currentFrametimes = currentFrametimes / weight;
currentFrametimes += timeSinceLastFrame;
}
}
您在创建变量时设置权重: (较高的重量对于瞬时帧速率更准确,重量更轻更平滑。我发现3-5是一个很好的平衡)
SmartFramerate smartFPS = new SmartFramerate(5);
在每个帧运行的任何地方调用Update方法:
smartFPS.Update(gameTime.ElapsedGameTime.TotalSeconds);
可以像这样访问当前帧速率:
smartFPS.framerate
或打印如下:
debuginfo.Update("\n\nᴥ" + smartFPS.framerate.ToString("0000"), true);
(我将它放入自定义打印类中,所以如果语法看起来很时髦,我会道歉)
但是,如果你想简单地将一定数量的帧放在一起,那么这个类就是我提出的最有效的方法。
class SmoothFramerate
{
int samples;
int currentFrame;
double[] frametimes;
double currentFrametimes;
public double framerate
{
get
{
return (samples / currentFrametimes);
}
}
public SmoothFramerate(int Samples)
{
samples = Samples;
currentFrame = 0;
frametimes = new double[samples];
}
public void Update(double timeSinceLastFrame)
{
currentFrame++;
if (currentFrame >= frametimes.Length) { currentFrame = 0; }
currentFrametimes -= frametimes[currentFrame];
frametimes[currentFrame] = timeSinceLastFrame;
currentFrametimes += frametimes[currentFrame];
}
}
要使用它,只需初始化您想要使用它的SmoothFramerate变量,传递您想要平均的帧数:
SmoothFramerate smoothFPS = new SmoothFramerate(1000);
更新,访问和打印当前帧速率,就像使用上面的SmartFramerate类一样。
感谢阅读,我希望这可以帮助别人。
答案 2 :(得分:1)
使用双倍来衡量fps:
double frameRate = 0.0;
修改方法Update
,如下所示:
public override void Update(GameTime gameTime)
{
if(gameTime.ElapsedGameTime.TotalSeconds > 0.0)
{
frameRate = (double)frameCounter / gameTime.ElapsedGameTime.TotalSeconds;
}
frameCounter = 0;
}
我没有测试代码,但你应该明白这个想法。
答案 3 :(得分:0)
您可能尝试在每次绘制操作中更新FPS。这将是非常不稳定的价值,因为有时您需要更多,有时更少。为了使价值更稳定 - 从许多价值中取平均值。
计算FPS的最简单方法可能是计算图纸。而且具有定时器功能的每秒可以说这个值,计算新的fps和清除计数器。使这个计时器更长(例如2秒),或者只是取最后10个fps值并显示平均值。
在一些游戏中,我看到他们也计算了重绘场景所需的最长时间。这也可能是一个有趣的价值。为此,您可以测量绘制函数需要多长时间:在开始时记录时间,最后记录时间差异。
注意,如果启用同步,则延迟绘制操作直到下次同步,这可能是奇怪结果的原因?
答案 4 :(得分:0)
更新每个Draw()的简单方法是:
frameRate = 1 / gameTime.ElapsedGameTime.TotalSeconds;
如果您愿意,也可以在Update()方法中删除它以查看触发频率。
如果你想减慢更新的速度......
frameRate += (((1 / gameTime.ElapsedGameTime.TotalSeconds) - frameRate) * 0.1);