ゲームを構成する要素は、

ブロック

ボール

バー

の三つです。

 

主な処理は、

描画については、

バーを描画する
ボールを描画する。
ブロックを描画する

 

他の主な処理は、
バーの移動
ボールの移動
ボールの当たり判定

 

に分けられます。

 

〇プログラム例

 

  1. #include <windows.h>
  2.  
  3. /* ゲームウィンドウの幅 */
  4. #define WND_WIDTH 640
  5. #define WND_HEIGHT 480
  6.  
  7. VOID StartGame(VOID); /* ゲームデータを初期化する */
  8. VOID EndGame(VOID); /* ゲームを終了する */
  9.  
  10. VOID Paint(HDC); /* ゲーム全体をペイントする */
  11. VOID PaintBackground(HDC); /* 背景を描画する */
  12. VOID PaintBar(HDC); /* バーを描画する */
  13. VOID PaintBall(HDC); /* ボールを描画する */
  14. VOID PaintBlocks(HDC); /* ブロックを描画する */
  15.  
  16. VOID MoveBall(VOID); /* ボールを次の位置へ移動させる */
  17.  
  18. HWND hMainWindow; /* アプリケーションウィンドウのハンドル */
  19.  
  20. int waitTime = 20;
  21.  
  22. BOOL isRun = FALSE; /* ゲームが実行されていればTRUE */
  23.  
  24. HBITMAP hBackBmp = NULL; /* 背景ビットマップ */
  25.  
  26. #define BLOCK_WIDTH 60 /* ブロックの幅 */
  27. #define BLOCK_HEIGHT 20 /* ブロックの高さ */
  28.  
  29. /* ブロックの現在の数(blocksポインタが参照する配列の長さ*/
  30. int blockCount;
  31.  
  32. /*
  33.     個々のブロックの情報を提供する構造体。
  34.     ブロックの位置とサイズは、
  35.     常にBALL_MOVEの倍数になるように設定します。
  36.     そうでなければ、当たり判定で不具合が生じます。
  37.     */
  38. typedef struct _tagBlock {
  39.     BOOL enable; /* ブロックが有効ならTRUE */
  40.     RECT bounds; /* ブロックの位置とサイズ */
  41. } BlockInfo;
  42. BlockInfo* blocks = NULL;
  43.  
  44. #define BAR_WIDTH 100 /* 操作するバーの幅 */
  45. /* 操作するバーの高さ。
  46.  この値はBALL_MOVEの倍数になるように設定してください
  47.  */
  48. #define BAR_HEIGHT 10
  49. POINT barLocation = { 300,400 }; /* バーの位置 */
  50.  
  51. #define BALL_MOVE 5 /* ボールの移動距離 */
  52. /* TRUEなら正の方向に、FALSEなら負の方向に移動する */
  53. BOOL ballX = TRUE, ballY = FALSE;
  54.  
  55. #define BALL_WIDTH 10 /* ボールの幅 */
  56. #define BALL_HEIGHT 10 /* ボールの高さ */
  57. POINT ballLocation = { 40,380 }; /*ボールの位置*/
  58.  
  59. VOID StartGame() {
  60.     int i, x, y;
  61.  
  62.     blockCount = 40; /* ブロック数は40 */
  63.     blocks = (BlockInfo*)malloc(sizeof(BlockInfo) * blockCount);
  64.  
  65.     x = BALL_WIDTH * 2;
  66.     y = BALL_HEIGHT * 2;
  67.     for (i = 0; i < blockCount; i++) {
  68.         blocks[i].enable = TRUE;
  69.         blocks[i].bounds.left = x;
  70.         blocks[i].bounds.top = y;
  71.         blocks[i].bounds.right = x + BLOCK_WIDTH;
  72.         blocks[i].bounds.bottom = y + BLOCK_HEIGHT;
  73.  
  74.         x += BLOCK_WIDTH;
  75.  
  76.         if (x > (WND_WIDTH - BLOCK_WIDTH-(BALL_WIDTH * 2))){
  77.             x = BALL_WIDTH * 2;
  78.             y += BLOCK_HEIGHT + BALL_MOVE;
  79.         }
  80.  
  81.  
  82.     }
  83.  
  84.     isRun = TRUE;
  85. }
  86.  
  87. VOID EndGame() {
  88.     isRun = FALSE;
  89.     if (blocks) {
  90.         blockCount = 0;
  91.         free(blocks);
  92.         blocks = NULL;
  93.     }
  94.  
  95.     /* 以下に、追加の終了処理を記述できます。*/
  96.  
  97. }
  98.  
  99. VOID Paint(HDC hdc) {
  100.     const RECT wndRect = { 0,0,WND_WIDTH, WND_HEIGHT };
  101.     FillRect(hdc, &wndRect, GetStockObject(BLACK_BRUSH));
  102.  
  103.     PaintBackground(hdc);
  104.     PaintBar(hdc);
  105.     PaintBlocks(hdc);
  106.     PaintBall(hdc);
  107. }
  108.  
  109. VOID PaintBackground(HDC hdc) {
  110.     if (hBackBmp) {
  111.         HDC hBackDC = CreateCompatibleDC(hdc);
  112.         SelectObject(hBackDC, hBackBmp);
  113.         BitBlt(hdc, 0, 0, WND_WIDTH, WND_HEIGHT, hBackDC, 0, 0, SRCCOPY);
  114.         DeleteDC(hBackDC);
  115.         DeleteObject(hBackDC);
  116.     }
  117. }
  118.  
  119. VOID PaintBar(HDC hdc) {
  120.     SelectObject(hdc, GetStockObject(BLACK_PEN));
  121.     SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  122.     Rectangle(hdc, barLocation.x, barLocation.y,
  123.         barLocation.x + BAR_WIDTH, barLocation.y + BAR_HEIGHT);
  124. }
  125.  
  126. VOID PaintBall(HDC hdc) {
  127.     SelectObject(hdc, GetStockObject(BLACK_PEN));
  128.     SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  129.     Ellipse(hdc, ballLocation.x, ballLocation.y,
  130.         ballLocation.x + BALL_WIDTH, ballLocation.y + BALL_HEIGHT);
  131. }
  132.  
  133. VOID PaintBlocks(HDC hdc) {
  134.     int i;
  135.  
  136.     if (!blocks) return;
  137.  
  138.     for (i = 0; i < blockCount; i++) {
  139.         if (!blocks[i].enable)
  140.             continue;
  141.         Rectangle(hdc, blocks[i].bounds.left, blocks[i].bounds.top,
  142.             blocks[i].bounds.right, blocks[i].bounds.bottom);
  143.     }
  144. }
  145.  
  146. VOID MoveBall() {
  147.     int i, enableBlockCount;
  148.  
  149.     if (ballX)
  150.         ballLocation.x += BALL_MOVE;
  151.     else
  152.         ballLocation.x -= BALL_MOVE;
  153.  
  154.     if (ballY)
  155.         ballLocation.y += BALL_MOVE;
  156.     else
  157.         ballLocation.y -= BALL_MOVE;
  158.  
  159.     /* 以下、ぼるのバウンド・当たり判定 */
  160.  
  161.     /* ボールが画面の端を超えた場合、跳ね返る */
  162.     if (ballLocation.x <= 0)
  163.         ballX = TRUE;
  164.     else if (ballLocation.x + BALL_WIDTH >= WND_WIDTH)
  165.         ballX = FALSE;
  166.  
  167.     if (ballLocation.y <= 0)
  168.         ballY = TRUE;
  169.     else if ( /*ボールがバーに当たったかどうか*/
  170.         ballLocation.y + BALL_HEIGHT >= barLocation.y &&
  171.         ballLocation.y <= barLocation.y + BAR_HEIGHT &&
  172.         ballLocation.x + BALL_WIDTH >= barLocation.x &&
  173.         ballLocation.x <= barLocation.x + BAR_WIDTH)
  174.         ballY = FALSE;
  175.  
  176.     /*ボールがブロックに当たったかどうか */
  177.     for (i = enableBlockCount = 0; i < blockCount; i++) {
  178.         if (blocks == NULL)
  179.             break;
  180.  
  181.         if (!blocks[i].enable) {
  182.             /* このブロックは既に無効である */
  183.             enableBlockCount++;
  184.             continue;
  185.         }
  186.  
  187.         if (ballLocation.y <= blocks[i].bounds.bottom &&
  188.             ballLocation.y + BALL_HEIGHT >= blocks[i].bounds.top) {
  189.             if (ballLocation.x + BALL_WIDTH == blocks[i].bounds.left) {
  190.                 ballX = FALSE;
  191.                 blocks[i].enable = FALSE;
  192.             }
  193.             else if (ballLocation.x == blocks[i].bounds.right) {
  194.                 ballX = TRUE;
  195.                 blocks[i].enable = FALSE;
  196.             }
  197.         }
  198.         if (ballLocation.x <= blocks[i].bounds.right &&
  199.             ballLocation.x + BALL_WIDTH >= blocks[i].bounds.left) {
  200.             if (ballLocation.y + BALL_HEIGHT == blocks[i].bounds.top) {
  201.                 ballY = FALSE;
  202.                 blocks[i].enable = FALSE;
  203.             }
  204.             else if (ballLocation.y == blocks[i].bounds.bottom) {
  205.                 ballY = TRUE;
  206.                 blocks[i].enable = FALSE;
  207.             }
  208.         }
  209.     }
  210.  
  211.     /* ボールが落ちた、またはブロックがすべて消えた */
  212.     if (ballLocation.y > WND_HEIGHT) {
  213.         EndGame();
  214.         /* 以下に、ゲームオバーの処理を追加できます */
  215.     }
  216.     else if (enableBlockCount == blockCount) {
  217.         EndGame();
  218.         /* 以下に、クリアの処理を追加できます */
  219.     }
  220. }
  221.  
  222. DWORD WINAPI ThreadFunc(LPVOID vdParam) {
  223.     HWND hWnd = (HWND)vdParam;
  224.     while (isRun) {
  225.         MoveBall();
  226.         InvalidateRect(hWnd, NULL, FALSE);
  227.         Sleep(waitTime);
  228.     }
  229.     return TRUE;
  230. }
  231.  
  232.  
  233. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  234. {
  235.  
  236.     HDC hdc;
  237.     PAINTSTRUCT ps;
  238.     static DWORD dwThreadID;
  239.  
  240.     /* ダブルバッファリング用のビットマップとデバイスコンテキスト */
  241.     static HBITMAP hWndBuffer;
  242.     static HDC hBufferDC;
  243.  
  244.     switch (uMsg)
  245.     {
  246.     case WM_DESTROY:
  247.         if (isRun)
  248.             EndGame();
  249.         DeleteDC(hBufferDC);
  250.         DeleteObject(hWndBuffer);
  251.         if (hBackBmp)
  252.             DeleteObject(hBackBmp);
  253.  
  254.         PostQuitMessage(0);
  255.         return 0;
  256.  
  257.     case WM_CREATE:
  258.         ShowWindow(hWnd, SW_SHOW);
  259.  
  260.         hMainWindow = hWnd;
  261.  
  262.         hdc=GetDC(hWnd);
  263.         hWndBuffer = CreateCompatibleBitmap(hdc, WND_WIDTH, WND_HEIGHT);
  264.         hBufferDC = CreateCompatibleDC(hdc);
  265.         SelectObject(hBufferDC, hWndBuffer);
  266.         ReleaseDC(hWnd, hdc);
  267.  
  268.         hBackBmp = LoadImage(NULL, TEXT("back.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  269.  
  270.         StartGame();
  271.         CreateThread(NULL, 0, ThreadFunc, (LPVOID)hWnd, 0, &dwThreadID);
  272.  
  273.         return 0;
  274.  
  275.     case WM_MOUSEMOVE:
  276.         barLocation.x = LOWORD(lParam) - (BAR_WIDTH / 2);
  277.         if (barLocation.x < 0)
  278.             barLocation.x = 0;
  279.         else if (barLocation.x + BAR_WIDTH > WND_WIDTH) {
  280.             barLocation.x = WND_WIDTH - BAR_WIDTH;
  281.         }
  282.         InvalidateRect(hWnd, NULL, FALSE);
  283.  
  284.         return 0;
  285.  
  286.     case WM_PAINT:
  287.         hdc = BeginPaint(hWnd, &ps);
  288.         Paint(hBufferDC);
  289.         BitBlt(hdc, 0, 0, WND_WIDTH, WND_HEIGHT, hBufferDC, 0, 0, SRCCOPY);
  290.         EndPaint(hWnd, &ps);
  291.         return 0;
  292.     }
  293.     return DefWindowProc(hWnd, uMsg, wParam, lParam);
  294.  
  295. }
  296.  
  297. int APIENTRY wWinMain(
  298.     _In_ HINSTANCE hInstance,
  299.     _In_opt_ HINSTANCE hPrevInstance,
  300.     _In_ LPWSTR ipCmdLine,
  301.     _In_ int nCmdShow
  302. ) {
  303.  
  304.     WNDCLASSEXW wcex;
  305.  
  306.     wcex.cbSize = sizeof(WNDCLASSEX);
  307.  
  308.     wcex.style = CS_HREDRAW | CS_VREDRAW;
  309.     wcex.lpfnWndProc = WndProc;
  310.     wcex.cbClsExtra = 0;
  311.     wcex.cbWndExtra = 0;
  312.     wcex.hInstance = hInstance;
  313.     wcex.hIcon = NULL;
  314.     wcex.hCursor = NULL;
  315.     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  316.     wcex.lpszMenuName = NULL;
  317.     wcex.lpszClassName = TEXT("TestWindow");
  318.     wcex.hIconSm = NULL;
  319.  
  320.     RegisterClassExW(&wcex);
  321.  
  322.     hMainWindow = CreateWindowEx(0UL, TEXT("TestWindow"), TEXT("日本"), WS_OVERLAPPEDWINDOW,
  323.         CW_USEDEFAULT, 0, 640, 480, NULL, NULL, hInstance, NULL);
  324.  
  325.     if (hMainWindow == NULL)
  326.     {
  327.         return FALSE;
  328.     }
  329.  
  330.     MSG msg;
  331.  
  332.     while (GetMessage(&msg, NULL, 0, 0) > 0) {
  333.         DispatchMessage(&msg);
  334.     }
  335.  
  336.     return (int)msg.wParam;
  337. }

※参考 Windowsゲームプログラミング

 

〇実行結果

 

これで一通り、Windowsゲームプログラミングを読むことができました。

古い本ですが、参考になるところは多かったと思います。