Вот как я это делаю и этим методом:
- Вы в среднем по n фреймов
- Вы можете использовать его с любым методом инициализации, который вы выберете
- Это должно быть легко читать и следовать
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace _60fps
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont OutputFont;
float Fps = 0f;
private const int NumberSamples = 50; //Update fps timer based on this number of samples
int[] Samples = new int[NumberSamples];
int CurrentSample = 0;
int TicksAggregate = 0;
int SecondSinceStart = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
graphics.SynchronizeWithVerticalRetrace = false;
int DesiredFrameRate = 60;
TargetElapsedTime = new TimeSpan(TimeSpan.TicksPerSecond / DesiredFrameRate);
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
OutputFont = Content.Load<SpriteFont>("MessageFont");
}
protected override void UnloadContent()
{/* Nothing to do */}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
this.Exit();
base.Update(gameTime);
}
private float Sum(int[] Samples)
{
float RetVal = 0f;
for (int i = 0; i < Samples.Length; i++)
{
RetVal += (float)Samples[i];
}
return RetVal;
}
private Color ClearColor = Color.FromNonPremultiplied(20, 20, 40, 255);
protected override void Draw(GameTime gameTime)
{
Samples[CurrentSample++] = (int)gameTime.ElapsedGameTime.Ticks;
TicksAggregate += (int)gameTime.ElapsedGameTime.Ticks;
if (TicksAggregate > TimeSpan.TicksPerSecond)
{
TicksAggregate -= (int)TimeSpan.TicksPerSecond;
SecondSinceStart += 1;
}
if (CurrentSample == NumberSamples) //We are past the end of the array since the array is 0-based and NumberSamples is 1-based
{
float AverageFrameTime = Sum(Samples) / NumberSamples;
Fps = TimeSpan.TicksPerSecond / AverageFrameTime;
CurrentSample = 0;
}
GraphicsDevice.Clear(ClearColor);
spriteBatch.Begin();
if (Fps > 0)
{
spriteBatch.DrawString(OutputFont, string.Format("Current FPS: {0}\r\nTime since startup: {1}", Fps.ToString("000"), TimeSpan.FromSeconds(SecondSinceStart).ToString()), new Vector2(10,10), Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Что касается:
«но вопрос, почему отображаемый FPS менялся чаще, чем раз в секунду, все еще открыт»
Разница между ElapsedGameTime и ElapsedRealTime заключается в том, что «ElapsedGameTime» - это количество времени, прошедшее с момента последнего ввода оператора Update или Draw (в зависимости от того, какой «gameTime» вы используете - тот из Update или тот из Update Draw).
ElapsedRealTime - время с момента начала игры. Из-за этого он увеличивается линейно, так как игра продолжает работать. Действительно, через 1 секунду вы обновите каждый кадр, потому что ваша логика выглядела так:
(Предположим, вы использовали 4 кадра в секунду для простоты объяснения):
- Кадр 1: ElapsedRealTime: 0,25. Текущий итог: 0,25
- Кадр 2: ElapsedRealTime: 0,5 Итого сейчас: 0,75
- Кадр 3: ElapsedRealTime: 0,75 Промежуточный итог сейчас: 1,5
- Итоговое значение больше 1 !!! Показать FPS!
- Set Промежуточный итог = 0
- Кадр 4: ElapsedRealTime: 1,00 Промежуточный итог сейчас: 1,0
- Итоговое значение больше 1 !!! Показать FPS!
Теперь, когда вы исправили счетчик, теперь вы должны получать только Elapsed Game Time с постоянными 0,25, поэтому прогрессия теперь движется:
- Кадр 1: ElapsedGameTime: 0,25. Текущий итог: 0,25
- Кадр 2: ElapsedGameTime: 0,25 Всего сейчас: 0,50
- Кадр 3: ElapsedGameTime: 0,25 Всего сейчас: 0,75
- Кадр 4: ElapsedGameTime: 0,25 Итого сейчас: 1,00
- Общая сумма больше 1 !!! Показать FPS!
Набор Промежуточный итог = 0
Кадр 5: ElapsedGameTime: 0,25. Промежуточный итог сейчас: 0,25
- Кадр 6: ElapsedGameTime: 0,25 Всего итогов сейчас: 0,50
- Кадр 7: ElapsedGameTime: 0,25 Всего сейчас: 0,75
- Кадр 8: ElapsedGameTime: 0,25 Всего сейчас: 1,00
- Итоговое значение больше 1 !!! Показать FPS!
- Set Промежуточный итог = 0
Что вы ожидаете? Короче говоря, теперь, когда вы исправили первую проблему, вы должны были исправить и вторую, и «почему» объясняется выше.