C语言俄罗斯方块(简易版)

来源:互联网 发布:高清网络解码器 编辑:程序博客网 时间:2024/04/30 22:39

本俄罗斯方块全部用绘图函数实现方块的绘制,没有一点资源,因此源代码很小巧,整个程序编译链接好,也就10K多吧。非常小巧的俄罗斯方块。

设计思想:
1、将游戏区域划分为18行*10列的棋盘,设立一个布尔型的二维数组变量,以表示棋盘上各个地方是否有方块。
2、用4个顶点代表各种不同形状的方块,一旦方块在游戏区域中,就把对应的布尔型二维数组变量置为真,表示该方格已经有方块了。
3、如上做方便方块移动是否会碰撞的判断。
4、代码已经修正了一个小BUG。
5、压缩包中的文件是未经修改的源代码,此处的代码为最新。
6、方向键上为改变形状,下为直接落到底部。p键为暂停(或者Pause键)

#include <windows.h> //为了使用API函数#include <time.h>//为了使用定时器#include <stdlib.h>  //为了使用随机数#define BLOCKWIDTH20  //单个方块大小#define NUMLINEBLOCKS18  //行数#define NUMCOLUMNBLOCKS10  //列数#define ID_TIMER1//定时器ID#define BLOCKSTYLES(sizeof (Blocks) / sizeof (Blocks[0]))  //方块的种类数//游戏区各方格顶点布尔值,代表该方格是否有方块boolGameClient[NUMCOLUMNBLOCKS][NUMLINEBLOCKS];static intF, S, cF, cS;//随机方块图形对应的第一、二纬static intScore;  //得分//定义各方块形状,以点表示struct  {POINTpt[4];}Blocks[][4] = {//正70, 0, 1, 0, 1, 1, 1, 2,  2, 0, 0, 1, 1, 1, 2, 1,  1, 0, 1, 1, 1, 2, 2, 2,  0, 1, 1, 1, 2, 1, 0, 2,//反71, 0, 2, 0, 1, 1, 1, 2,  0, 1, 1, 1, 2, 1, 2, 2,  1, 0, 1, 1, 0, 2, 1, 2,  0, 0, 0, 1, 1, 1, 2, 1,//11, 0, 1, 1, 1, 2, 1, 3,  0, 1, 1, 1, 2, 1, 3, 1,  1, 0, 1, 1, 1, 2, 1, 3,  0, 1, 1, 1, 2, 1, 3, 1,//Z0, 0, 1, 0, 1, 1, 2, 1,  2, 0, 1, 1, 2, 1, 1, 2,  0, 0, 1, 0, 1, 1, 2, 1,  2, 0, 1, 1, 2, 1, 1, 2,//反Z1, 0, 2, 0, 0, 1, 1, 1,  1, 0, 1, 1, 2, 1, 2, 2,  1, 0, 2, 0, 0, 1, 1, 1,  1, 0, 1, 1, 2, 1, 2, 2,//田字0, 0, 1, 0, 0, 1, 1, 1,  0, 0, 1, 0, 0, 1, 1, 1,  0, 0, 1, 0, 0, 1, 1, 1,  0, 0, 1, 0, 0, 1, 1, 1,//尖头1, 0, 0, 1, 1, 1, 2, 1,  0, 0, 0, 1, 1, 1, 0, 2,  0, 0, 1, 0, 2, 0, 1, 1,  1, 0, 0, 1, 1, 1, 1, 2};LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){WNDCLASS wndcls;TCHAR szClassName[] = TEXT("Terics"),  szWindowName[] = TEXT("Aka's Terics");static POINT Block[4];wndcls.cbClsExtra= 0;wndcls.cbWndExtra= 0;wndcls.hbrBackground= static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));wndcls.hCursor= LoadCursor(hInstance, IDC_ARROW);wndcls.hIcon= LoadIcon(hInstance, IDI_APPLICATION);wndcls.hInstance= hInstance;wndcls.lpfnWndProc= WndProc;wndcls.lpszClassName= szClassName;wndcls.lpszMenuName= NULL;wndcls.style= CS_HREDRAW | CS_VREDRAW;RegisterClass(&wndcls);HWND hwnd = CreateWindow(szClassName, szWindowName, WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,CW_USEDEFAULT, CW_USEDEFAULT, (NUMCOLUMNBLOCKS + 10) * BLOCKWIDTH,(NUMLINEBLOCKS + 3) * BLOCKWIDTH,NULL, NULL, hInstance, NULL);ShowWindow(hwnd, SW_SHOWNORMAL);UpdateWindow(hwnd);MSG msg;while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}//随机数函数定制版,用于随机出现的方块unsigned Random(int n);//判断是否可以下落,可以则返回truebool CanDown(POINT pt[]);//下落实现void Down(POINT pt[]);//判断是否可以左移bool CanLeft(POINT pt[]);//实现左移void Left(POINT pt[]);//判断是否可以右移bool CanRight(POINT pt[]);//实现右移void Right(POINT pt[]);//判断是否可以变形bool CanChange(POINT pt[]);//实现变形void Change(POINT pt[]);//消行处理以及分数结算void DelSqure(HWND);LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){POINTTericsBorder[] = {-1, -1, NUMCOLUMNBLOCKS * BLOCKWIDTH + 1, NUMLINEBLOCKS * BLOCKWIDTH + 1};HDChdc;PAINTSTRUCTps;TEXTMETRICtm;TCHARszNextTerics[] = TEXT("下一个:"),szSCore[] = TEXT("得分:");static TCHAR szBufferScore[5];static intcxChar, cyChar;static POINT Block[4], NextBlock[4];intx, y;static boolpause = false;  //暂停switch(message){case WM_CREATE:hdc = GetDC(hwnd);GetTextMetrics(hdc, &tm);cxChar = tm.tmAveCharWidth * 2;cyChar = tm.tmExternalLeading + tm.tmHeight;SetTimer(hwnd, ID_TIMER, 600, NULL);//初始化第一个出现的方块cS = Random(4);cF = Random(BLOCKSTYLES);for(int i = 0; i < 4; ++i){Block[i].x = Blocks[cF][cS].pt[i].x + 4;Block[i].y = Blocks[cF][cS].pt[i].y;GameClient[Block[i].x][Block[i].y] = true;}S = Random(4);F = Random(BLOCKSTYLES);for(int i = 0; i < 4; ++i){NextBlock[i].x = Blocks[F][S].pt[i].x;NextBlock[i].y = Blocks[F][S].pt[i].y;}ReleaseDC(hwnd, hdc);return 0;case WM_TIMER:if(pause) return 0;if(CanDown(Block)){Down(Block);}//不能下移,需要处理消行判断(结合分数),还需要处理下一个显示,和当前显示的方块else{DelSqure(hwnd);for(int i = 0; i < 4; ++i){Block[i].x = NextBlock[i].x + 4;Block[i].y = NextBlock[i].y;if(GameClient[Block[i].x][Block[i].y]){KillTimer(hwnd, ID_TIMER);}elseGameClient[Block[i].x][Block[i].y] = true;}cS = S;  cF = F;S = Random(4);F = Random(BLOCKSTYLES);for(int i = 0; i < 4; ++i){NextBlock[i].x = Blocks[F][S].pt[i].x;NextBlock[i].y = Blocks[F][S].pt[i].y;}}InvalidateRect(hwnd, NULL, TRUE);return 0;case WM_KEYDOWN:if(pause && wParam != VK_PAUSE) return 0;switch(wParam){case VK_LEFT:if(CanLeft(Block))Left(Block);InvalidateRect(hwnd, NULL, TRUE);break;case VK_RIGHT:if(CanRight(Block))Right(Block);InvalidateRect(hwnd, NULL, TRUE);break;case VK_UP:if(CanChange(Block))Change(Block);InvalidateRect(hwnd, NULL, TRUE);break;case VK_DOWN:while(CanDown(Block))Down(Block);InvalidateRect(hwnd, NULL, TRUE);break;case VK_PAUSE:pause = !pause;break;default:break;}return 0;case WM_CHAR:if(wParam == 'p')pause = !pause;else if(wParam == 'r'){Score = 0;for(int x = 0; x < NUMCOLUMNBLOCKS; ++x){for(int y = 0; y < NUMLINEBLOCKS; ++y)GameClient[x][y] = false;}cS = Random(4);cF = Random(BLOCKSTYLES);for(int i = 0; i < 4; ++i){Block[i].x = Blocks[cF][cS].pt[i].x + 4;Block[i].y = Blocks[cF][cS].pt[i].y;GameClient[Block[i].x][Block[i].y] = true;}S = Random(4);F = Random(BLOCKSTYLES);for(int i = 0; i < 4; ++i){NextBlock[i].x = Blocks[F][S].pt[i].x;NextBlock[i].y = Blocks[F][S].pt[i].y;}pause = false;InvalidateRect(hwnd, NULL, TRUE);}return 0;case WM_PAINT://if(pause) return 0;hdc = BeginPaint(hwnd, &ps);SetViewportOrgEx(hdc, BLOCKWIDTH, BLOCKWIDTH, NULL);SelectObject(hdc, GetStockObject(WHITE_BRUSH));SelectObject(hdc, GetStockObject(BLACK_PEN));//画俄罗斯方块游戏的边框Rectangle(hdc, TericsBorder[0].x, TericsBorder[0].y,TericsBorder[1].x, TericsBorder[1].y);//输出“下一个”字符串TextOut(hdc, (NUMCOLUMNBLOCKS + 1) * BLOCKWIDTH, 0, szNextTerics, lstrlen(szNextTerics));//输出“得分”字符串TextOut(hdc, (NUMCOLUMNBLOCKS + 1) * BLOCKWIDTH, cyChar + 5 * BLOCKWIDTH,szSCore, lstrlen(szSCore));//SetTextAlign(hdc, TA_RIGHT | TA_TOP);TextOut(hdc, (NUMCOLUMNBLOCKS + 1) * BLOCKWIDTH + 3 * cxChar, 2 * cyChar + 5 * BLOCKWIDTH,szBufferScore, wsprintf(szBufferScore, TEXT("%d"), Score));SetTextAlign(hdc, TA_LEFT | TA_TOP);SelectObject(hdc, GetStockObject(BLACK_BRUSH));SelectObject(hdc, GetStockObject(WHITE_PEN));//显示游戏区的方块for(x = 0; x < NUMCOLUMNBLOCKS; ++x){for(y = 0; y < NUMLINEBLOCKS; ++y){if(GameClient[x][y]){Rectangle(hdc, x * BLOCKWIDTH, y * BLOCKWIDTH,(x + 1) * BLOCKWIDTH, (y + 1) * BLOCKWIDTH);}}}//显示下一个方块区域的方块for(int i = 0; i < 4; ++i){Rectangle(hdc, (NextBlock[i].x + NUMCOLUMNBLOCKS + 2) * BLOCKWIDTH, NextBlock[i].y * BLOCKWIDTH + cyChar,(NextBlock[i].x + NUMCOLUMNBLOCKS + 3) * BLOCKWIDTH, (NextBlock[i].y + 1) * BLOCKWIDTH + cyChar);}EndPaint(hwnd, &ps);return 0;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc(hwnd, message, wParam, lParam);}//判断方块是否可以下落bool CanDown(POINT pt[]){bool result = true;//将方块所在格子先假设指定为无方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = false;for(int i = 0; i < 4; ++i){//假如继续落下超过下底边界,返回false;或者假如该小方块下落一格已经有方块,结果为falseif(pt[i].y + 1 == NUMLINEBLOCKS || GameClient[pt[i].x][pt[i].y + 1]){result = false;break;}}//恢复方块所在格子为有方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = true;return result;}//判断是否可以左移bool CanLeft(POINT pt[]){bool result = true;//将方块所在格子先假设指定为无方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = false;for(int i = 0; i < 4; ++i){//假如继续左移超过左边边界,返回false;或者假如该小方块左移一格已经有方块,结果为falseif(!pt[i].x || GameClient[pt[i].x - 1][pt[i].y]){result = false;break;}}//恢复方块所在格子为有方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = true;return result;}//判断是否可以右移bool CanRight(POINT pt[]){bool result = true;//将方块所在格子先假设指定为无方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = false;for(int i = 0; i < 4; ++i){//假如继续左移超过左边边界,返回false;或者假如该小方块左移一格已经有方块,结果为falseif(pt[i].x + 1 == NUMCOLUMNBLOCKS || GameClient[pt[i].x + 1][pt[i].y]){result = false;break;}}//恢复方块所在格子为有方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = true;return result;}//判断是否可以旋转bool CanChange(POINT pt[]){bool result = true;//将方块所在格子先假设指定为无方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = false;int t = (cS + 1) % 4;for(int k = 0; k < 4; ++k){int x = Blocks[cF][t].pt[k].x - Blocks[cF][cS].pt[k].x,y = Blocks[cF][t].pt[k].y - Blocks[cF][cS].pt[k].y;if(GameClient[pt[k].x + x][pt[k].y + y] ||  //该方格已经有方块pt[k].x + x > NUMCOLUMNBLOCKS - 1 ||  //x坐标超越了右边界pt[k].x + x < 0 ||   //x坐标超越了左边界pt[k].y + y > NUMLINEBLOCKS - 1)  //y坐标超越了下底边界{result = false;break;}}//恢复方块所在格子为有方块for(int i = 0; i < 4; ++i)GameClient[pt[i].x][pt[i].y] = true;return result;}//实现旋转void Change(POINT pt[]){int t = (cS + 1) % 4;for(int i = 0; i < 4; ++i){int x = Blocks[cF][t].pt[i].x - Blocks[cF][cS].pt[i].x,y = Blocks[cF][t].pt[i].y - Blocks[cF][cS].pt[i].y;GameClient[pt[i].x][pt[i].y] = false;pt[i].x += x;pt[i].y += y;GameClient[pt[i].x][pt[i].y] = true;}cS = t;}//实现右移void Right(POINT pt[]){for(int i = 0; i < 4; ++i){GameClient[pt[i].x][pt[i].y] = false;++pt[i].x;}for(int k = 0; k < 4; ++k)GameClient[pt[k].x][pt[k].y] = true;}//实现左移void Left(POINT pt[]){for(int i = 0; i < 4; ++i){GameClient[pt[i].x][pt[i].y] = false;--pt[i].x;}for(int k = 0; k < 4; ++k)GameClient[pt[k].x][pt[k].y] = true;}//实现方块的下落void Down(POINT pt[]){for(int i = 0; i < 4; ++i){GameClient[pt[i].x][pt[i].y] = false;++pt[i].y;}for(int k = 0; k < 4; ++k)GameClient[pt[k].x][pt[k].y] = true;}//随机数函数定制版inline unsigned Random(int n){SYSTEMTIME st;GetLocalTime(&st);srand(st.wMilliseconds);return rand() % n;}//消行处理以及分数结算void DelSqure(HWND hwnd){int line = 0, temp;for(int x = NUMLINEBLOCKS - 1; x >= 0; --x){bool result = true;for(int y = 0; y < NUMCOLUMNBLOCKS; ++y){if(!GameClient[y][x]){result = false;break;}}//判断是否可以消行if(result){temp = x;++line;while(x > 0){for(int y = 0; y < NUMCOLUMNBLOCKS; ++y){GameClient[y][x] = GameClient[y][x - 1];}--x;}for(int y = 0; y < NUMCOLUMNBLOCKS; ++y)GameClient[y][0] = false;x = temp + 1;}}if(line)Score += (line - 1) * 2 + 1;InvalidateRect(hwnd, NULL, TRUE);}


原创粉丝点击