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