「FPSカウンター」タグのついた投稿

最近Unityを使う事があるので、Unity嫌いにも関わらず、気が向いた時にUnity関連のメモを書くことにしました。

今回は、GUI TextにFPSを表示させるスクリプトについてメモります。ちなみに、Unityメモで書くコードは全てC#にする予定です (C# ラブ!)

GUITextのゲームオブジェクトを作る自体は簡単なので、スクリプトだけ解説します。

まず、必要な変数を宣言します。

public class FPSCounter : MonoBehaviour
{
public float m_updateInterval = 1.0f;  // 更新される頻度
float m_accumulated   = 0.0f;
float m_timeUntilNextInterval; //  次の更新までの残り時間
int m_numFrames = 0;

次に、Start()メソッド内で、FPSを更新させる頻度を初期化します。頻度は、エディター上から変更できます。

void Start()
{
m_timeUntilNextInterval = m_updateInterval;
}

次に、Update()メソッドで、FPSの更新処理を実装します。まずは、更新までの時間を経過した時間分減らし、フレーム数を加算します。

 void Update()
{
m_timeUntilNextInterval -= Time.deltaTime;
m_accumulated += Time.timeScale / Time.deltaTime;
++m_numFrames;

そして、更新までの時間が0を切ったら、FPSを更新します。この部分で、FPSの計算と、次の更新までの時間をリセットします。

if( m_timeUntilNextInterval <= 0.0 )
{
// FPSの計算と表示
float fps = m_accumulated / m_numFrames;
string format = System.String.Format( "FPS: {0:F2}", fps );
guiText.text = format;

m_timeUntilNextInterval = m_updateInterval;
m_accumulated = 0.0F;
m_numFrames = 0;
}
}

スクリプトは以上です。後は、GUI Textのゲームオブジェクトをシーン内に追加し、スクリプトを足してください。

 

実行結果は、以下の用になります:

前に書いたGameComponentのメモの続きです。

今回は、Game1登録したらUpdate()だけでなくDraw()メソッドも自動で呼ばれるGameComponentの作り方を乗せます。

XNAには描画も出来るGameComponentが既に備わっています。GameComponentクラスの代わりに、DrawableGameComponentクラスを継承するとLoadContent()メソッドとDraw()メソッドをオーバーライドできます。Initialize()とUpdate()同様Game1内のbase.メソッド名()で順番に呼ばれます。

 

今回は前に作ったFPSカウンターのクラスで実装例を書きます。まず、FPSカウンターのクラスで、DrawableGameComponentクラスを継承し、コンストラクタも書きます。

class FPSCounter : DrawableGameComponent
{
float m_fps;    // 実際のFPS
float m_interval; // FPSの更新速度(殆どの場合は1秒)
float m_updateTimer; // 更新するまでを計るタイマー
int m_frameCount; // 現在のフレーム数

SpriteBatch m_spriteBatch;
SpriteFont m_font;

public FPSCounter(Game game)
: base(game)
{
m_fps = 0.0f;
m_interval = 1.0f;
m_updateTimer = 0.0f;
m_frameCount = 0;
}

次に、LoadContent()メソッドをオーバーライドします。

protected override void LoadContent()
{
m_spriteBatch = new SpriteBatch(Game.GraphicsDevice);
m_font = Game.Content.Load<SpriteFont>("Font");
base.LoadContent();
}

そして、Draw()メソッドをオーバーライドします。

public override void Draw(GameTime gameTime)
{
// フレーム数を増やす(目標は1秒に60回)
m_frameCount++;

// タイマーに前のフレームから過ぎた時間を加算する
m_updateTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;

// タイマーが1秒を超えたら
if (m_updateTimer > m_interval)
{
// FPSを計算する, 速度が下がっていた場合はここで差を計算する
m_fps = m_frameCount / m_updateTimer;

// タイマーとカウンターをリセットする
m_frameCount = 0;
m_updateTimer -= m_interval;
}

// FPSの数値を描画する
m_spriteBatch.Begin();
m_spriteBatch.DrawString(m_font, string.Format("FPS: {0:F2}", m_fps), new Vector2(0, 0), Color.Black);
m_spriteBatch.DrawString(m_font, string.Format("FPS: {0:F2}", m_fps), new Vector2(1, 1), Color.White);
m_spriteBatch.End();

base.Draw(gameTime);
}
} // クラス実装終了

今回は紹介していませんが、GameComponent同様Initialize()とUpdate()メソッドもオーバーライド出来ます。

最後に、Game1クラス内で、FPSカウンターを登録します。

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";

// Inputクラスをコンポーネントとして、登録する
Components.Add(new Input(this));

// FPSクラスを描画できるコンポーネントとして、登録する
Components.Add(new FPSCounter(this));
}

これで、Game1でDraw()メソッドを呼ばなくても、自動的にFPSが描画されます(SpriteFontは事前にプロジェクトに追加しましたので、そのままコピペしても動きません)。

今回は以上です。

前回に「ゲームの状態変更の実装方法3」を書くような事を言いましたが、気が向かなかったので今回はFPSカウンターの作り方メモります。ちなみに、XNA前提で書かれています。

FPSとは大体の場合は1秒間に何フレーム(コマ)描画されたかをあらわす数字です。ゲームでは基本的に60、もしくは30を目標としている場合が多いです(細かいことを書くと違う気がしますが、今回は良いことにしときます)。

これを計算するには基本的に:

–       描画される毎に(Draw()メソッドが呼ばれるたび)フレーム数を上げる

–       1秒ごとにFPSを計算する(式はフレーム数 / 経過時間)

–       フレーム数をリセットする

を繰り返すことです。

 

上記をXNAで実装するには、まず新しいクラスを作り、各変数を宣言します。

class FPSCounter
{
float m_fps;    // 実際のFPS
float m_interval; // FPSの更新速度(殆どの場合は1秒)
float m_updateTimer; // 更新するまでを計るタイマー
int m_frameCount; // 現在のフレーム数

public FPSCounter()
{
m_fps = 0.0f;
m_interval = 1.0f;
m_updateTimer = 0.0f;
m_frameCount = 0;
}
 

このクラスでのFPS計算はGame1内のDraw()メソッドで処理します。なので、FPSカウンター内では計算と描画(FPSを画面に表示)を同じメソッドで行います。行う処理は、上で説明したのと同じで、最後に描画処理を足しただけです。

// Game1内のDraw()メソッドで呼んでください
public void Draw(SpriteBatch sp, SpriteFont font, float delta)
{
// フレーム数を増やす(目標は1秒に60回)
m_frameCount++;

// タイマーに前のフレームから過ぎた時間を加算する
m_updateTimer += delta;

// タイマーが1秒を超えたら
if (m_updateTimer > m_interval)
{
// FPSを計算する, 速度が下がっていた場合はここで差を計算する
m_fps = m_frameCount / m_updateTimer;

// タイマーとカウンターをリセットする
m_frameCount = 0;
m_updateTimer -= m_interval;
}

// FPSの数値を描画する
sp.DrawString(font, "FPS: " + m_fps, new Vector2(0, 0), Color.White);
}
 

後は、Game1クラス内で、FPSカウンターを作り、Draw()メソッドを呼ぶだけです。

// 前のフレームから経過した時間を獲得する(秒で)
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
spriteBatch.Begin();
fps.Draw(spriteBatch, font, delta);
spriteBatch.End();
 

これで、画面の左上にFPSが表示されます。描画をする前に、SpriteFontを作製し、読み込むのを忘れないようにしてください。

ちなみに、実際に起動してみるとFPSはかなり高い可能性で59.9999…のような長い数字になります。これをもっと見やすくするには、FPSの描画を以下に変更してみてください。

sp.DrawString(font, string.Format("FPS: {0:F2}", m_fps), new Vector2(0, 0), Color.White);
 

これにより、FPSの小数点は以下は2つまでしか描画されなくなります(string.Format()については、MSDNをご参照ください)。

実装後はこんな感じになります(左上にFPSが出ています)。

以上です。ちなみに、上の動画では見やすくするためにFPSの描画を違う色で二回しています。

 

前にも書きましたが、最近ネタが思いつかないのでリクエストがあったらコメントか、メールをお送りください m_ _m

その他にも、質問や間違い、ツッコミどころがあればコメントをください。