一派掌門 二十級              | 
          
            
            
             
              【Invader.cpp】 #include <stdio.h> #include <Windows.h> #include "Invader.h"
  static unsigned char charset[16 * 8] = {     /* invader(0) */     0x00, 0x00, 0x00, 0x43, 0x5f, 0x5f, 0x5f, 0x7f,     0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x20, 0x3f, 0x00,
      /* invader(1) */     0x00, 0x0f, 0x7f, 0xff, 0xcf, 0xcf, 0xcf, 0xff,     0xff, 0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0x00,
      /* invader(2) */     0x00, 0xf0, 0xfe, 0xff, 0xf3, 0xf3, 0xf3, 0xff,     0xff, 0x07, 0xff, 0xff, 0x03, 0x03, 0x03, 0x00,
      /* invader(3) */     0x00, 0x00, 0x00, 0xc2, 0xfa, 0xfa, 0xfa, 0xfe,     0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x04, 0xfc, 0x00,
      /* fighter(0) */     0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,     0x01, 0x43, 0x47, 0x4f, 0x5f, 0x7f, 0x7f, 0x00,
      /* fighter(1) */     0x18, 0x7e, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xff,     0xff, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0x00,
      /* fighter(2) */     0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,     0x80, 0xc2, 0xe2, 0xf2, 0xfa, 0xfe, 0xfe, 0x00,
      /* laser */     0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 }; /* invader:"abcd", fighter:"efg", laser:"h" */
  HWND hWnd; struct INVADER {     int fighter_x; // 自機的坐標     int laser_x, laser_y; // 等離子炮彈的坐標     int invaders_x, invaders_y; // 外星人群的坐標     int invaders_direction; // 外星人群的移動方向     int laserwait; // 等離子炮彈的剩餘充電時間     int movewait; // 為0時外星人群前進一步     int movewait0; // movewait的初始值(消滅30隻敵人後減少)     int invaders_line; // 外星人群的行數     int score; // 當前得分     int high; // 最高得分     int point; // 得分的增加量(獎金的單價)     char invaders_str[32 * 6]; // 將外星人群的狀態顯示為字符串的變量     int flags; // 遊戲狀態 } invader;
  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {     WNDCLASSEX wcex;     wcex.cbSize = sizeof(WNDCLASSEX);     wcex.cbClsExtra = 0;     wcex.cbWndExtra = 0;     wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // 窗口的背景為黑色     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);     wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);     wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);     wcex.hInstance = hInstance;     wcex.lpfnWndProc = WndProc;     wcex.lpszClassName = "WC_Invader";     wcex.lpszMenuName = NULL;     wcex.style = NULL;     RegisterClassEx(&wcex);
      // 根據客戶區大小計算窗口大小     DWORD style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;     RECT rect;     rect.left = rect.top = 0;     rect.right = 323;     rect.bottom = 227;     AdjustWindowRect(&rect, style, NULL);
      HWND hWnd = CreateWindow(wcex.lpszClassName, "Invader", style, CW_USEDEFAULT, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);     if (!hWnd)         return 1;     ShowWindow(hWnd, nCmdShow);     UpdateWindow(hWnd);
      MSG msg;     while (GetMessage(&msg, NULL, 0, 0))     {         TranslateMessage(&msg);         DispatchMessage(&msg);     }     return msg.wParam; }
  LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {     switch (uMsg)     {     case WM_CREATE:         ::hWnd = hWnd;         restart();         break;     case WM_DESTROY:         KillTimer(hWnd, IDT_TIMER1);         PostQuitMessage(0);         break;     case WM_KEYDOWN:         keyboard_handler(wParam);         break;     case WM_PAINT:         wnd_paint();         break;     default:         return DefWindowProc(hWnd, uMsg, wParam, lParam);     }     return FALSE; }
  void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT iTimerID, DWORD dwTime) {     if (invader.laserwait != 0)         invader.laserwait--; // 等離子炮的充電時間保證了每次只能發射一粒炮彈     invaders_move();     laser_move(); }
  void gameover(void) {     KillTimer(hWnd, IDT_TIMER1);     invader.flags |= F_GAMEOVER;     update_gameover(); }
  void invaders_move(void) {     if (invader.movewait != 0)     {         invader.movewait--;         return;     }     invader.movewait = invader.movewait0;     if (invader.invaders_x + invader.invaders_direction > 14 || invader.invaders_x + invader.invaders_direction < 0)     {         if (invader.invaders_y + invader.invaders_line == 13)         {             gameover();             return;         }         invader.invaders_direction = -invader.invaders_direction;         invader.invaders_y++;     }     else         invader.invaders_x += invader.invaders_direction;     update_invaders(); }
  void keyboard_handler(WPARAM wParam) {     switch (wParam)     {     case 0x0d:         // enter         if (invader.flags & F_GAMEOVER)         {             invader.flags &= ~F_GAMEOVER;             restart();             update();         }         break;     case 0x20:     case 0x26:         // space         if (invader.laserwait == 0)         {             invader.laserwait = 15;             invader.laser_x = invader.fighter_x + 1;             invader.laser_y = 13;         }         break;     case 0x25:     case 0x64:         // left         if (invader.fighter_x > 0)         {             invader.fighter_x--;             update_fighter();         }         break;     case 0x27:     case 0x66:         // right         if (invader.fighter_x < 37)         {             invader.fighter_x++;             update_fighter();         }     } }
  void laser_move(void) {     if (invader.laser_y <= 0)         return; // 如果invader.laser_y已經降至0, 則不執行任何操作
      invader.laser_y--;     update_laser();     if (invader.laser_y == 0)     {         // 當invader.laser_y降至0的瞬間         invader.point -= 10;         if (invader.point <= 0)             invader.point = 1;     }     if (invader.invaders_x < invader.laser_x && invader.laser_x < invader.invaders_x + 25 && invader.invaders_y <= invader.laser_y && invader.laser_y < invader.invaders_y + invader.invaders_line)     {         int pos = (invader.laser_y - invader.invaders_y) * 32 + invader.laser_x - invader.invaders_x;         if (invader.invaders_str[pos] != ' ')         {             // 擊中             invader.score += invader.point;             invader.point++;             if (invader.high < invader.score)                 invader.high = invader.score;             update_score();             while (pos >= 0 && invader.invaders_str[pos] != ' ')                 pos--; // pos的最小值為-1                          memset(&invader.invaders_str[pos + 1], ' ', 4);             update_invader_hit();                          while (invader.invaders_line > 0)             {                 for (pos = (invader.invaders_line - 1) * 32; invader.invaders_str[pos] != '\0'; pos++)                 {                     if (invader.invaders_str[pos] != ' ')                     {                         // 有存活的情況下                         invader.laser_y = 0;                         return;                     }                 }                 invader.invaders_line--;             }
              // 全部消滅的情況下             invader.movewait0 -= invader.movewait0 / 3; // 加速             next_group();             update_invaders();         }     } }
  void next_group(void) {     static char invader_str0[32] = " abcd abcd abcd abcd abcd ";     invader.invaders_x = 7;     invader.invaders_y = 1;     invader.invaders_line = 6;     invader.laser_y = 0;     invader.movewait = invader.movewait0;     invader.invaders_direction = 1;
      int i, j;     for (i = 0; i < invader.invaders_line; i++)     {         for (j = 0; j < 27; j++)             invader.invaders_str[i * 32 + j] = invader_str0[j];     } }
  void putimg(HDC hdc, RECT *rcPaint, int x, int y, COLORREF color, LPCSTR imgstr) {     x *= 8;     y *= 16;
      int i, j;     int x0, y0;     while (*imgstr != '\0')     {         if (x > rcPaint->right)             return;         if (*imgstr >= 'a' && *imgstr <= 'h')         {             int pos = 16 * (*imgstr - 'a');             for (i = 0; i < 16; i++)             {                 if ((y0 = y + i) > rcPaint->bottom)                     break;                 if (y0 < rcPaint->top)                     continue;                 for (j = 0; j < 8; j++)                 {                     if ((x0 = x + j) > rcPaint->right)                         break;                     if (x0 < rcPaint->left)                         continue;                     if (charset[pos + i] & _BV(7 - j))                         SetPixel(hdc, x0, y0, color);                 }             }         }         imgstr++;         x += 8;     } }
  void putstr(HDC hdc, int x, int y, LPCSTR str) {     TextOut(hdc, x * 8, y * 16, str, strlen(str)); }
  void restart(void) {     invader.score = 0;     invader.point = 1;     invader.movewait0 = 20;     invader.fighter_x = 18;     next_group();     SetTimer(hWnd, IDT_TIMER1, 40, TimerProc); }
  // 更新整個遊戲畫面 void update(void) {     RECT rect;     GetClientRect(hWnd, &rect);     InvalidateRect(hWnd, &rect, TRUE); }
  // 更新自機部分的畫面 void update_fighter(void) {     // 擦除屏幕上y>=208的區域並重新繪製     RECT rect;     GetClientRect(hWnd, &rect);     rect.top = 208;     InvalidateRect(hWnd, &rect, TRUE); }
  // 更新GAME OVER文字 void update_gameover(void) {     RECT rect;     rect.left = 120;     rect.top = 96;     rect.right = 264;     rect.bottom = 112;     InvalidateRect(hWnd, &rect, TRUE); }
  // 更新擊中的外星人那一行畫面 void update_invader_hit(void) {     RECT rect;     GetClientRect(hWnd, &rect);     rect.top = invader.laser_y * 16;     rect.bottom = rect.top + 16;     InvalidateRect(hWnd, &rect, FALSE); }
  // 更新顯示全部外星人的那部分畫面 void update_invaders(void) {     RECT rect;     GetClientRect(hWnd, &rect);     rect.top = 16;     rect.bottom = 207;     InvalidateRect(hWnd, &rect, FALSE); }
  // 更新等離子炮彈那部分畫面 void update_laser(void) {     RECT rect;     rect.left = invader.laser_x * 8;     rect.top = invader.laser_y * 16;     rect.right = rect.left + 8;     rect.bottom = rect.top + 32;     InvalidateRect(hWnd, &rect, FALSE); }
  // 更新顯示得分信息的那部分畫面 void update_score(void) {     RECT rect;     GetClientRect(hWnd, &rect);     rect.bottom = 16;     InvalidateRect(hWnd, &rect, FALSE); }
  // 窗口繪製 void wnd_paint(void) {     RECT rect;     GetClientRect(hWnd, &rect);     PAINTSTRUCT ps;     HDC hdc = BeginPaint(hWnd, &ps);     HDC hdcMem = CreateCompatibleDC(hdc);     HBITMAP hbmpMem = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);     SelectObject(hdcMem, hbmpMem);          // 繪製分數     SetBkColor(hdcMem, COL_BLACK);     if (ps.rcPaint.top <= 16)     {         char str[15];         SetTextColor(hdcMem, COL_WHITE);         sprintf_s(str, "HIGH:%08d", invader.high);         putstr(hdcMem, 22, 0, str);         sprintf_s(str, "SCORE:%08d", invader.score);         putstr(hdcMem, 4, 0, str);     }
      // 繪製外星人     int i;     for (i = 0; i < invader.invaders_line; i++)     {         putimg(hdcMem, &ps.rcPaint, invader.invaders_x, invader.invaders_y + i, COL_GREEN, invader.invaders_str + i * 32);     }
      putimg(hdcMem, &ps.rcPaint, invader.fighter_x, 13, COL_CYAN, "efg"); // 繪製自機     if (invader.laser_y > 0) // 確保炮彈不會出現在顯示分數的那一欄         putimg(hdcMem, &ps.rcPaint, invader.laser_x, invader.laser_y, COL_YELLOW, "h"); // 繪製炮彈
      // 繪製GAME OVER字樣     if (invader.flags & F_GAMEOVER)     {         SetTextColor(hdcMem, COL_RED);         putstr(hdcMem, 15, 6, "GAME OVER");     }
      BitBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdcMem, rect.left, rect.top, SRCCOPY);     EndPaint(hWnd, &ps);     DeleteDC(hdcMem);     DeleteObject(hbmpMem); }              
             |