第6章 キャラクタ表示の様々なテクニック

6−3 メッセージウインドウにFPSの表示

ゲームプログラミングではWindowsプログラミング(イベント・ドリブン方式)と違い、イベントとは関係なくループし続ける。
これをゲーム・ループと呼ぶ。(詳しくは第2章を参照)
では、このゲームループはどれくらいのスピードで回っているのだろうか?

そこで、ゲームループがどれくらいのスピードで回っているかを計測する。スピードは、1秒間に何回ループするか(FPS)で考える。

1秒間に何回ループするかを調べるには、ゲームループが始まる前に0をセットし、ゲームループが一回ループするたびにカウントアップする。1秒たったら何回ループしたかを表示すればよい。

ここで問題になるのは、1秒たったどうかをどうやって調べるかである。
Windowsにはマシンを起動してからどれだけ時間がたっているかを調べるAPI関数として「TimeGetTime関数」「GetTickCount関数」がある。この関数を使い、ゲーム開始時とループ途中の経過時間を調べ、差分が1秒(1000ミリ秒)を超えるかどうかで判断する。

プログラムに組み込むには、WinMain.cpp内で行うのがよい。

【プログラム例】

//=============================================================================
//      2Dゲーム基本プログラム3(第6章キャラクタ表示テスト用プログラム)
//=============================================================================
#include "common.h"

//-----------------------------------------------------------------------------
// プロトタイプ宣言
//-----------------------------------------------------------------------------
・
・
・

//-----------------------------------------------------------------------------
// 外部変数(本体)
//-----------------------------------------------------------------------------
・
・
・

//-----------------------------------------------------------------------------
// グローバル変数
//-----------------------------------------------------------------------------
static char szWinName[] = "Skeleton";  // ウィンドウクラス名
static char szTitle[] = "2Dゲーム基本プログラム3";  // ウィンドウタイトル名
static DWORD backTickCount, nowTickCount;  // 時間制御用

//=============================================================================
//      ウィンドウメイン関数(WinMain)
//=============================================================================
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
    HWND    hWnd;
    MSG     msg;

    /* 表示するウィンドウの定義、登録、表示 */
    if (!(hWnd = InitApp(hThisInst, nWinMode)))
        return FALSE;

    /* Direct Draw Object の初期化 */
    if (InitializeDraw(hWnd) != DD_OK)
        return FALSE;

    /* FPSの初期設定 */
    backTickCount = 0;

    /* ゲーム・ループ */
    while (TRUE)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))  // メッセージがあるかどうか
        {
            if (!GetMessage(&msg, NULL, 0, 0))  // メッセージを取得し、WM_QUITかどうか
                break;
            TranslateMessage(&msg);  //キーボード利用を可能にする
            DispatchMessage(&msg);   //制御をWindowsに戻す
        }
        else  // ゲームメイン処理
        {
            UpdateFrame(hWnd);
            Sleep(1);
        }
    }

    return msg.wParam;

}

//=============================================================================
//      ウィンドウプロシジャ関数(WindowProcedure)
//=============================================================================
static LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    ・
    ・
    ・

}

//=============================================================================
//  関数名 :InitApp
//  機能概要:表示するウィンドウの定義、登録、表示
//  戻り値 :正常終了のとき1、以上終了のとき0
//=============================================================================
static HWND InitApp(HINSTANCE hThisInst, int nWinMode)
{
    ・
    ・
    ・

}

//-----------------------------------------------------------------------------
// 関数名 : UpdateFrame()
// 機能概要: 画面更新処理
//-----------------------------------------------------------------------------
static void UpdateFrame(HWND hWnd)
{
    static int fps = 0;  // FPSカウント
    char buff[80];  // 文字列表示用バッファ

    /* 現在のキー情報を取得 */
    if (!GetKeyboardState(KeyTbl))
        return;

    /* 現在の時間を取得 */
    nowTickCount = timeGetTime();

    /* 処理の振り分け */
    switch (g_FrameNo)
    {
        case START_INIT:
            StartInit(hWnd);
        case START_FRAME:
            StartFrame(hWnd);
            break;
        case GAME_INIT:
            GameInit(hWnd);
        case GAME_FRAME:
            GameFrame(hWnd);
            break;
        default:
            OutputDebugString("g_FrameNoの値が例外です。\n");
    }

    /* FPSを求めて表示する */
    fps++;
    if (nowTickCount - backTickCount >= 1000)
    {
        backTickCount = nowTickCount;
        wsprintf(buff, "%04d FPS\n", fps);
        OutputDebugString(buff);
        fps = 0;
    }

    /* フリップ処理 */
    g_pDDSPrimary->Flip(NULL, 0);

}

ビルド後、デバッグ・モードで実行(F5キー)すると、OutputDebugString関数により、約1秒ごとにメッセージ・ウィンドウにFPSが出力される
プログラム実行中はメッセージ・ウィンドウを見ることはできないので、プログラム終了後に確認する。

初めは数値が安定しないが、すぐに60FPS前後に固定されることが分かる。

■6-3確認問題(必須)

プログラムを修正し、FPSが画面に表示されるかどうかを確認する。


[ TOP ]