//main.cpp #include "Backdrop.h" #include "tool.h" Frame *yard = new Backdrop(GAME_WIDTH, GAME_HEIGHT, GetModuleHandle(NULL)); LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return yard->EventHandler(hWnd, message, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { yard->CreateFrame(); return yard->Run(); } //tool.h #pragma once #include<windows.h> const int GAME_WIDTH = 600; const int GAME_HEIGHT = 800; const int ROWS = 24; const int COLS = 17; const int BOX_WIDTH = GAME_WIDTH / COLS; const int BOX_HEIGHT = GAME_HEIGHT / ROWS; void FillRect(HDC hDC,HBRUSH hbr,int x,int y, int width, int height) { RECT r; r.left = x; r.right= x + width; r.top = y; r.bottom = y+height; FillRect(hDC,&r,hbr); } //frame.h #pragma once #include <windows.h> #include "tool.h" extern LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); class Frame { public: bool CreateFrame(); virtual void Draw(HDC hdc){} virtual void KeyDown(WPARAM wParam){} virtual void KeyUp(){} LRESULT EventHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); Frame(){} Frame(int w, int h, HINSTANCE hInst) { width = w; height = h; hInstance = hInst; } int Run() { MSG msg; PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); while (msg.message != WM_QUIT) { DWORD tNow = GetTickCount(); if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else if(tNow - tPre >= 200) { InvalidateRect (hWnd, NULL, FALSE); //KeyDown(m_wParam); } } return (int) msg.wParam; } DWORD tPre; WPARAM m_wParam; HWND hWnd; protected: int width; int height; HINSTANCE hInstance; //双缓冲 HDC memDC; HBITMAP hBmp; }; bool Frame::CreateFrame() { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = "RussianBlock"; wcex.lpszClassName = "RussianBlock"; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wcex); hWnd = CreateWindow("RussianBlock", "RussianBlock",WS_OVERLAPPEDWINDOW , 100, 100, width, height, NULL, NULL, hInstance, NULL); //RECT rt; //rt.left = 100; //rt.top = 100; //rt.right = 100 +width; //rt.bottom = 100 + height; //AdjustWindowRect(&rt, WS_OVERLAPPEDWINDOW, false); if (!hWnd) { return FALSE; } ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); //创建双缓冲dc和位图 memDC = CreateCompatibleDC(GetDC(hWnd)); hBmp = CreateCompatibleBitmap(memDC, width, height); SelectObject(memDC, hBmp); return TRUE; } LRESULT Frame::EventHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_CREATE: //SetTimer (hWnd, 1, 150, NULL) ; break; case WM_TIMER : // MessageBeep (-1) ; //InvalidateRect (hWnd, NULL, FALSE); break; case WM_KEYDOWN: KeyDown(wParam); m_wParam = wParam; break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码...; FillRect(memDC,(HBRUSH)GetStockObject(WHITE_BRUSH), 0, 0, width, height); //画到memDC中 Draw(memDC); BitBlt(hdc, 0, 0, width, height, memDC, 0, 0, SRCCOPY);//内存的memDC->hdc EndPaint(hWnd, &ps); tPre = GetTickCount(); break; case WM_DESTROY: //KillTimer (hWnd, 1) ; PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } //block.h #pragma once #include "tool.h" #include "Backdrop.h" class Backdrop; int blockAreaAll[7][4][4] = { { { 0,0,0,0 },{ 0,1,1,0 },{ 1,1,0,0 },{ 0,0,0,0 } }, { { 0,0,0,0 },{ 1,1,0,0 },{ 0,1,1,0 },{ 0,0,0,0 } }, { { 0,0,0,0 },{ 0,1,1,1 },{ 0,1,0,0 },{ 0,0,0,0 } }, { { 0,0,0,0 },{ 1,1,1,0 },{ 0,0,1,0 },{ 0,0,0,0 } }, { { 0,0,0,0 },{ 0,1,1,0 },{ 0,1,1,0 },{ 0,0,0,0 } }, { { 0,0,0,0 },{ 0,1,0,0 },{ 1,1,1,0 },{ 0,0,0,0 } }, { { 0,0,0,0 },{ 1,1,1,1 },{ 0,0,0,0 },{ 0,0,0,0 } }, }; int blockArea[4][4]= { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} }; int blockTemp[4][4]; class Block { public: Block(){} Block(int col, int row) { this->col = col; this->row = row; getRandomBlockArea(); } void setRow(int r) { this->row=r; } void setCol(int c ) { this->col=c; } int GetRow() const { return row; } int GetCol() const { return col; } void Draw(HDC hdc); void KeyDown(WPARAM wParam); void CheckLeftBound(); void CheckRightBound(); void RotateBlock();//旋转 void getBlockArea(int b[4][4]); void RandomRotateBlock(int n); void ClearBlockArea() { for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { blockArea[i][j]=0; } } } void getRandomBlockArea() { getBlockArea(blockAreaAll[rand()%7]);//随机得到一个方块 RandomRotateBlock(rand()%4); //随机转一圈 } private: int col,row; int w, h; int L_Col,R_Col; }; void Block::Draw(HDC hdc) { for(int i = row - 2; i < row + 2; i++) { for(int j = col - 2; j < col + 2; j++) { if(blockArea[i - (row - 2)][j - (col - 2)]) FillRect(hdc, (HBRUSH)GetStockObject(BLACK_BRUSH), j*BOX_WIDTH, i*BOX_HEIGHT, BOX_WIDTH, BOX_HEIGHT); /*else FillRect(hdc, (HBRUSH)GetStockObject(2), j*BOX_WIDTH, i*BOX_HEIGHT, BOX_WIDTH, BOX_HEIGHT);*/ } } row++; CheckLeftBound(); CheckRightBound(); } void Block::KeyDown(WPARAM wParam) { switch (wParam) { case VK_LEFT: if(L_Col<=0) L_Col=0; else col--; break; case VK_UP: RotateBlock(); break; case VK_RIGHT: if(R_Col>=COLS) R_Col=COLS; else col++; break; case VK_DOWN: row++; break; //case VK_RETURN: // if(bPlay == true) // bPlay=false; // else // bPlay=true; // break; //SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0) ; } } void Block::RandomRotateBlock(int n) { for(int i=0;i<n;i++) { RotateBlock(); } } void Block::RotateBlock() { //清空blockTemp for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { blockTemp[i][j]=0; } } //旋转值 存到 Temp for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { blockTemp[i][j]=blockArea[3-j][i]; } } //blockArea得到结果 for(int i = 0; i < 4; i++) { for(int j=0;j<4;j++) { blockArea[i][j]=blockTemp[i][j]; } } } void Block::getBlockArea(int b[4][4]) { ClearBlockArea(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { if(b[i][j]) blockArea[i][j]=b[i][j]; } } } void Block::CheckLeftBound() { for(int j = col - 2; j < col + 2; j++) { for(int i = row - 2; i < row + 2; i++) { if(blockArea[i - row + 2][j - col + 2]) { L_Col=j; return ; } } } } void Block::CheckRightBound() { for(int j = col + 2; j > col - 2; j--) { for(int i = row + 2; i > row - 2; i--) { if(blockArea[i - row + 2][j - col + 2]) { R_Col=j; return ; } } } } //backdrop.h #pragma once #include"Frame.h" #include"tool.h" #include"Block.h" #include <vector> using namespace std; //class Block; class Backdrop : public Frame { public: HBRUSH hBrush ; Backdrop(){} Backdrop(int w, int h, HINSTANCE hInst) { width = w; height = h; hInstance = hInst; gameover = false; for(int i = 0; i < ROWS; i++) { for(int j = 0; j < COLS; j++) { backdropArea[i][j] = 0; } } bk = new Block(10, 0); } void Draw(HDC hdc); void KeyDown(WPARAM wParam); void KeyUp(); void DrawAll(HDC hdc) { for(int i = 0; i < ROWS; i++) { for(int j = 0; j < COLS; j++) { if(backdropArea[i][j]) { FillRect(hdc, (HBRUSH)GetStockObject(BLACK_BRUSH), j*BOX_WIDTH, i*BOX_HEIGHT, BOX_WIDTH, BOX_HEIGHT); } } } } //core logic void CheckStop() { int row = bk->GetRow(); int col = bk->GetCol(); for(int i = row + 1,k1=0; i > row - 2;k1++, i--) { bool flag=false,flag1=false; for(int j = col - 2,k2=0; j < col + 2;k2++ ,j++) { if(blockArea[3-k1][k2]&&backdropArea[i+1][j]&&i==0)//结束游戏 { gameover=true; flag1=true; break; } if(blockArea[3-k1][k2]&&i+2==ROWS||blockArea[3-k1][k2]&&backdropArea[i+1][j]) //比较触底)或者比较触块 { for(int r = row - 2,k3=0;r < row + 2;r++,k3++) { for(int c=col-2,k4=0;c<col+2;c++,k4++) { if(blockArea[k3][k4]) { backdropArea[r][c] = blockArea[k3][k4]; flag=true; } } } if(flag&&!flag1){ReStart();break;;} } } if(flag)break; } } //bool isRemoveLine() //{ // for(int i = ROWS - 1; i >= 0; i--) // { // bool b = true; // int j; // for(j = 0; j <= COLS - 1; j++) // { // if(backdropArea[i][j] != 1) // b=false; // break; // } // if(j == COLS) // { // return true; // } // } // return false; //} //思路:从下到上查找全1的行,存入vector,根据vector存的index"从上到下"每消除上面的一行其余的依次行下移(效率不怎么样),index【0】补零 void RemoveLine() { //查"1"(下->上) vector<int> vi; for(int i = ROWS - 1; i >= 0; i--) { bool b = true; for(int j = 0; j < COLS - 1; j++) { if(backdropArea[i][j] != 1) { b = false; break; } } if(b==true) { vi.push_back(i); } } //消行(上->下) for(int i = vi.size() - 1; i >= 0; i--) { for(int j = vi[i]; j > 0; j--) { for(int k = 0; k < COLS; k++) { backdropArea[j][k] = 0; backdropArea[j][k] = backdropArea[j-1][k]; } for(int k = 0; k < COLS; k++) backdropArea[0][k] = 0; } } } void ReStart() { bk->ClearBlockArea(); bk->setCol(10); bk->setRow(0); bk->getRandomBlockArea(); } bool gameover; Block *bk; //背景2维数组 int backdropArea[ROWS][COLS]; }; void Backdrop::Draw(HDC hdc) { //画出横线 //for(int i=0; i<ROWS; i++) //{ // MoveToEx(hdc, 0, BOX_HEIGHT * i, NULL); // LineTo(hdc, COLS * BOX_HEIGHT, BOX_HEIGHT * i); //} //for(int i=0; i<COLS; i++) //{ // // MoveToEx(hdc, BOX_WIDTH * i, 0, NULL); // LineTo(hdc, BOX_WIDTH * i, BOX_WIDTH * ROWS); //} if(!gameover) { bk->Draw(hdc); CheckStop(); RemoveLine(); } else { TextOut(hdc,0, 0, "游戏结束",strlen("游戏结束")); } DrawAll(hdc); } void Backdrop::KeyDown(WPARAM wParam) { bk->KeyDown(wParam); } void Backdrop::KeyUp() { }