ゲームプログラムのメモ書き

WindowsAPI

画面のちらつき防止

game.h

//リンカの追加
#pragma comment( lib, "winmm.lib" )

//定数宣言
#define APP_NAME "ちらつき防止"   //アプリケーション名
#define WINDOW_S ( WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX )
#define WINDOW_W 640    //ウインドウ幅
#define WINDOW_H 480    //ウインドウ高さ
#define FPS 60  //フレーム数

//構造体宣言
typedef struct GameWindow{
    HWND hWnd;      //ウインドウ
    HDC hScreenDC;  //バックバッファ
    SIZE size;      //サイズ
    DWORD dwFps;    //FPS
} GameWindow;

main.cpp

#include <windows.h>
#include <time.h>
#include "game.h"

/////////////////////////////////////////////////
//スレッド関数
/////////////////////////////////////////////////
DWORD WINAPI ThreadFunc(LPVOID vdParam)
{

    GameWindow *gameWnd;
    DWORD frames = 0, beforeTime;   //フレーム数と以前の時間
    char str[8] = {0};  //FPSの表示用

    //================== 初期処理 ==================//

    //乱数ジェネレータの初期化
    srand((unsigned)time(NULL));

    gameWnd = (GameWindow*) vdParam;    //渡された値の取得
    beforeTime = timeGetTime();         //時間の取得

    //================== ゲームループ ==================//
    while(IsWindow(gameWnd -> hWnd))
    {

        DWORD nowTime, progress, idealTime;
        nowTime = timeGetTime();    //現在の時間を取得
        progress = nowTime - beforeTime;    //経過時間を算出
        idealTime = (DWORD)(frames * (1000.0F/gameWnd -> dwFps));   //理想時間の算出

        //---------------- ゲーム処理 --------------//





        //----------------- 描画処理 ---------------//


        //描画の時間待ち
        if(idealTime > progress)
        {
            Sleep(idealTime - progress);
        }

        //FPSの表示位置
        TextOut(gameWnd->hScreenDC, 10, 10, str, lstrlen(str));

        //ウインドウの再描画
        InvalidateRect(gameWnd->hWnd, NULL, FALSE); //TRUE:画面初期化

        //1秒経過
        if(progress >= 1000)
        {
            wsprintf(str, "FPS = %d", frames);
            beforeTime = nowTime;   //時間変更
            frames = 0; //フレーム数初期化
        }
        frames++;
    }//whileの最後

    DeleteDC(gameWnd->hScreenDC);

    return TRUE;
}

/////////////////////////////////////////////////
//  ウインドウ関数
/////////////////////////////////////////////////
LRESULT CALLBACK WindowProc(
    HWND hWnd,          // ウインドウハンドル
    UINT uMsg,          // メッセージ
    WPARAM wParam,      // メッセージに対する情報
    LPARAM lParam) {    // メッセージに対する情報


    HDC hdc;        // デバイスコンテキスト
    PAINTSTRUCT ps; // 描画構造体

    static GameWindow gameWnd;
    static HBITMAP hBitmap;//BITMAPハンドル
    DWORD dwID; //スレッドID

    //--メッセージ別の処理
    switch(uMsg){
        case WM_DESTROY:

            // アプリケーションの終了をWindowsに通知する
            PostQuitMessage(0);
            return 0;

        case WM_CREATE:

            gameWnd.hWnd = hWnd;
            gameWnd.size.cx = WINDOW_W; //ウインドウ幅
            gameWnd.size.cy = WINDOW_H; //ウインドウ高さ
            gameWnd.dwFps = FPS;        //FPS

            //HDCの作成
            hdc = GetDC(hWnd);
            hBitmap = CreateCompatibleBitmap(hdc,
                gameWnd.size.cx,
                gameWnd.size.cy);

            gameWnd.hScreenDC = CreateCompatibleDC(hdc);
            SelectObject (gameWnd.hScreenDC, hBitmap);

            ReleaseDC(hWnd, hdc);   //hdcの解放

            //スレッドの作成と実行
            CreateThread(NULL,      //ハンドルを他のプロセスと共有する場合
                0,                  //スタックサイズ(デフォルト:0)
                ThreadFunc,         //スレッド関数名
                (LPVOID)&gameWnd,   //スレッドに渡す構造体
                0,                  //0:作成と同時に実行
                &dwID);             //スレッドID
        
            return 0;

        case WM_PAINT:
        
            //描画開始
            hdc = BeginPaint(hWnd,&ps);

            //スレッド内で作成された画像を描画
            BitBlt(hdc,
                0, 0,
                gameWnd.size.cx,
                gameWnd.size.cy,
                gameWnd.hScreenDC,
                0, 0,
                SRCCOPY);

            //描画終了
            EndPaint(hWnd, &ps);
            
            return 0;
    }
    // メインに返す情報
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

/////////////////////////////////////////////////
//  メイン関数
/////////////////////////////////////////////////
int WINAPI WinMain(
        HINSTANCE hInstance,    //インスタンス番号
        HINSTANCE hPrevInstance,
        PSTR lpCmdLine,
        int nCmdShow) {

    HWND hWnd;      //ウインドウハンドル
    WNDCLASS wc;    //ウインドウクラス構造体
    MSG msg;        //メッセージ

    /* ウインドウクラスの登録 */
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WindowProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = NULL;
    wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;    //背景色
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APP_NAME;

    // Windowsに登録
    if(!RegisterClass(&wc))
    {
        MessageBox(NULL,
            "ウインドウクラスの作成に失敗しました",
            "エラーメッセージ", MB_OK);
        return 0;
    }

    // ウインドウの作成
    hWnd = CreateWindow(
        APP_NAME,
        "sample",   // ウインドウタイトル
        WINDOW_S,           // ウインドウの設定
        CW_USEDEFAULT,
        CW_USEDEFAULT,  // 表示位置X,Y
        WINDOW_W, WINDOW_H, // 幅、高さ
        NULL,
        NULL,           // メニューの設定
        hInstance,
        NULL);

    if(hWnd == NULL)
    {
        MessageBox(NULL,
            "ウインドウの作成に失敗しました",
            "エラーメッセージ", MB_OK);
        return 0;
    }
        
    // ウインドウの表示
    ShowWindow(hWnd, SW_SHOW);

    // メッセージループ
    while(GetMessage(&msg, NULL, 0, 0) > 0){
        DispatchMessage(&msg);
    }

    return 0;
}