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; }