【Unity】FPSCounter (FPS表示) コンポーネントの作り方

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

Unityを触り始めた頃って、つい Update() に「移動処理」「入力処理」「UI更新」「デバッグ表示」…と、全部を詰め込みがちですよね。動いているうちは良いのですが、だんだんと

  • 何がどこで更新されているのか分からない
  • ちょっとした修正で他の処理が壊れる
  • パフォーマンスのボトルネックが追えない

といった問題にぶつかります。

特に「ゲームが重い気がする」「どのくらいFPSが出ているのか知りたい」といったとき、巨大な GameManager の一部にFPS計測ロジックをねじ込んでしまうと、あとで分離するのが大変です。

そこでこの記事では、「FPS表示だけ」を責務に持つ小さなコンポーネントとして、画面隅に現在のフレームレートを表示する FPSCounter を作っていきます。どのシーンにも簡単に追加できて、プレイヤーや敵のロジックとは完全に独立した「デバッグ用UI」として使えるようにしておきましょう。

【Unity】軽量デバッグHUDで快適計測!「FPSCounter」コンポーネント

今回作る FPSCounter は、

  • 一定間隔でFPSを計測して
  • UI Text(TextMeshPro)に表示し
  • 画面の好きな隅に固定表示できる

という、小さなデバッグ専用コンポーネントです。

フルコード(Unity6 / C#)


using UnityEngine;
using TMPro; // TextMeshPro を使う場合

/// <summary>
/// 現在のFPS(フレームレート)を画面隅に表示するコンポーネント。
/// ・TextMeshProUGUI を使った軽量なデバッグ用HUD
/// ・Update に全部書かず、「FPS表示」という責務だけを担当
/// </summary>
[DisallowMultipleComponent]
public class FPSCounter : MonoBehaviour
{
    // ==== 参照設定 ====

    [Header("表示先")]
    [Tooltip("FPSを表示する TextMeshProUGUI コンポーネント")]
    [SerializeField] private TextMeshProUGUI fpsLabel;

    // ==== 表示設定 ====

    [Header("更新間隔")]
    [Tooltip("FPSを何秒ごとに更新するか(例: 0.5秒ごとに計測)")]
    [SerializeField] private float updateInterval = 0.5f;

    [Header("小数点以下の桁数")]
    [Tooltip("FPS表示の小数点以下の桁数(0 にすると整数表示)")]
    [SerializeField] private int decimalPlaces = 0;

    [Header("色分けしきい値")]
    [Tooltip("このFPS以上なら goodColor で表示")]
    [SerializeField] private float goodFpsThreshold = 55f;

    [Tooltip("このFPS未満なら badColor で表示(その間は warnColor)")]
    [SerializeField] private float badFpsThreshold = 30f;

    [Header("表示色")]
    [SerializeField] private Color goodColor = Color.green;
    [SerializeField] private Color warnColor = Color.yellow;
    [SerializeField] private Color badColor = Color.red;

    [Header("ラベル設定")]
    [Tooltip("ラベルのプレフィックス(例: \"FPS:\") 空文字なら数値のみ表示")]
    [SerializeField] private string prefix = "FPS: ";

    // ==== 内部状態 ====

    private float timeAccumulator = 0f; // 経過時間の蓄積
    private int frameCount = 0;         // 経過フレーム数
    private float currentFps = 0f;      // 直近で計測したFPS

    private void Reset()
    {
        // コンポーネント追加時に、同じGameObject上の TextMeshProUGUI を自動取得しておく
        if (fpsLabel == null)
        {
            fpsLabel = GetComponent();
        }
    }

    private void Awake()
    {
        // fpsLabel が未設定の場合は、同じ GameObject から探す
        if (fpsLabel == null)
        {
            fpsLabel = GetComponent();
        }

        if (fpsLabel == null)
        {
            Debug.LogWarning(
                "[FPSCounter] TextMeshProUGUI が割り当てられていません。" +
                "Canvas 上の TextMeshProUGUI をアタッチしてください。",
                this
            );
        }

        // updateInterval が 0 以下にならないようにガード
        if (updateInterval <= 0f)
        {
            updateInterval = 0.5f;
        }

        // 小数点以下の桁数も最低0に制限
        if (decimalPlaces < 0)
        {
            decimalPlaces = 0;
        }
    }

    private void Update()
    {
        // FPS計測用の蓄積処理
        timeAccumulator += Time.unscaledDeltaTime; // TimeScale の影響を受けないよう unscaled を使用
        frameCount++;

        // 一定時間ごとにFPSを更新
        if (timeAccumulator >= updateInterval)
        {
            // 平均FPS = 経過フレーム数 / 経過時間
            currentFps = frameCount / timeAccumulator;

            // 次の計測に向けてリセット
            timeAccumulator = 0f;
            frameCount = 0;

            // ラベル更新
            UpdateLabel();
        }
    }

    /// <summary>
    /// FPS表示用ラベルのテキストと色を更新する。
    /// </summary>
    private void UpdateLabel()
    {
        if (fpsLabel == null)
        {
            return;
        }

        // 小数点以下の桁数に応じてフォーマット
        string format = decimalPlaces > 0
            ? "F" + decimalPlaces.ToString()
            : "F0";

        string fpsText = currentFps.ToString(format);

        // プレフィックス + FPS値 の形で表示
        fpsLabel.text = prefix + fpsText;

        // FPSに応じて色分け
        if (currentFps >= goodFpsThreshold)
        {
            fpsLabel.color = goodColor;
        }
        else if (currentFps < badFpsThreshold)
        {
            fpsLabel.color = badColor;
        }
        else
        {
            fpsLabel.color = warnColor;
        }
    }

    /// <summary>
    /// 現在のFPS値を取得したい場合に外部から参照できるプロパティ。
    /// (例: 他のデバッグUIと連携したいときなど)
    /// </summary>
    public float CurrentFps => currentFps;
}

使い方の手順

ここでは、画面右上にFPSを表示するデバッグラベルを例に、セットアップ手順①〜④を説明します。プレイヤーや敵のオブジェクトには一切触らず、「デバッグ用Canvas」にだけ追加していきます。

① Canvas と TextMeshPro の準備

  1. メニューから GameObject > UI > Canvas を作成します(既にある場合はそれを利用)。
  2. 同じくメニューから GameObject > UI > Text - TextMeshPro を作成し、Canvas の子にします。
    初回は TextMeshPro のインポートダイアログが出るので、指示に従って導入しておきましょう。
  3. 作成された Text オブジェクトの名前を FPSLabel など、分かりやすい名前に変更します。

② アンカーを画面隅に固定する

  1. FPSLabel を選択し、RectTransform の「Anchor Presets」を開きます。
  2. 右上に固定したい場合は、Alt+Shift を押しながら「右上」のプリセットをクリックします。
    (左上・右下・左下にしたい場合は、それぞれの隅のプリセットを選びます)
  3. Position の X / Y を調整して、画面の端から少し内側(例: X = -10, Y = -10)に配置します。
  4. フォントサイズ・色・フォントアセットなども、見やすいように調整しておきましょう。

③ FPSCounter コンポーネントを追加する

  1. FPSLabel オブジェクトを選択した状態で、Add Component をクリック。
  2. FPSCounter を検索し、追加します。
  3. インスペクター上で、Fps Label フィールドに自分自身の TextMeshProUGUI をドラッグ&ドロップします。
    Reset() で自動取得も試みますが、明示的に設定しておくと安心です)
  4. 更新間隔(Update Interval)や、色分けのしきい値(Good Fps Threshold / Bad Fps Threshold)を好みに合わせて調整します。

④ 実行してFPSを確認する

  1. Playボタンを押すと、設定した画面隅に「FPS: 60」などのラベルが表示されます。
  2. ゲーム内でオブジェクト数を増やしたり、ポストエフェクトをオン・オフしてみて、FPSの変化を確認してみましょう。
  3. ビルド後の実機でも同じラベルが表示されるので、PCとモバイルのパフォーマンス差を簡単に比較できます。

このように、「FPS表示」はあくまで UI専用の小さなコンポーネントとして分離しておくと、プレイヤーの移動ロジックや敵AIとは完全に独立して管理できます。

メリットと応用

FPSCounter をコンポーネントとして独立させることで、以下のようなメリットがあります。

  • どのシーンにも簡単に再利用できる
    一度プレハブ化しておけば、シーンにドラッグ&ドロップするだけでFPS表示が有効になります。
    巨大な GameManager に手を入れる必要がないので、安全に追加・削除できます。
  • レベルデザイン時のパフォーマンス計測が楽になる
    ステージに敵やエフェクトを追加しながら、「この辺りでFPSが落ちるな」といった感覚をリアルタイムに確認できます。
    重くなりそうなギミック(大量のパーティクル、動く床、NavMeshAgent を使う敵など)を配置するときの指標になります。
  • 責務が明確でテストしやすい
    「FPS表示だけ」を担当しているので、バグが出たときも原因の切り分けが簡単です。
    例えば、「FPSラベルが表示されない」問題は、このコンポーネントかUI設定を見ればよく、ゲームロジック側を疑う必要がありません。

応用として、一定FPSを下回ったときだけ警告を出すといった使い方もできます。例えば、下記のような「警告ログを出す」メソッドを追加すれば、ビルド後のログから重い場面を特定しやすくなります。


    /// <summary>
    /// FPSがしきい値を下回ったときに、ログで警告を出す例。
    /// (UpdateLabel() の最後などから呼び出して使う想定)
    /// </summary>
    private void LogLowFpsWarning(float threshold)
    {
        if (currentFps < threshold)
        {
            Debug.LogWarning(
                $"[FPSCounter] FPS が {threshold} を下回りました: {currentFps:F1}",
                this
            );
        }
    }

このように、小さなコンポーネントを積み重ねていくと、デバッグ機能やユーティリティ系の機能を安全に追加・削除できるようになります。
FPS表示も「巨大なマネージャーの一部」ではなく、独立した FPSCounter として育てていきましょう。

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

URLをコピーしました!