俄罗斯方块code

来源:互联网 发布:劳拉克劳馥 知乎 编辑:程序博客网 时间:2024/05/20 17:26
#include<windows.h>#include<winuser.h>#include<time.h>#include<mmsystem.h>#include"resource.h"#include"rect.h"const int FSIZE = 22 ; //方块大小int    m , n;int    Rstate[10][23]; //记录方块的位置int    Cstate[10][23]; //记录对应的位置的颜色int    Sx, Sy;HBRUSH Color[9]; //9种颜色画刷int    icolor; int    PrevShape, PrevColor; //记录预览窗口的图形的形状和对应的颜色,用于下一次在游戏窗口画出同样的图形int    Px, Py; //记录预览框中图形的位置,之所以这样是因为要保持其位置不变,以免刷新时图形移出预览框struct sRect{int x, y, dir, shape;}Pos;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevShapeInstance, PSTR szCmdLine, int iCmdShow){static TCHAR szAppName[] = TEXT("Tetris");HWND         hwnd;MSG          msg;WNDCLASS     winclass;winclass.style         = 0;winclass.lpfnWndProc   = WinProc;winclass.cbClsExtra    = 0;winclass.cbWndExtra    = 0;winclass.hInstance     = hInstance;winclass.hIcon         = LoadIcon(hInstance, (LPCSTR)ID_ICON);winclass.hCursor       = LoadCursor(NULL, NULL);winclass.hbrBackground = CreateSolidBrush(RGB(27,65,61));winclass.lpszClassName = szAppName;winclass.lpszMenuName  = (LPCSTR)ID_MENU;if(!RegisterClass(&winclass)){MessageBox(NULL,TEXT("创建窗口失败!"),TEXT("错误"),MB_OK);return 0;}hwnd = CreateWindow(szAppName, TEXT("~俄罗斯方块~"),                 WS_SYSMENU|WS_CAPTION,                         500, 200, 400, 590, NULL, NULL, hInstance, NULL);    ShowWindow(hwnd,iCmdShow);    UpdateWindow(hwnd);    while(GetMessage(&msg,NULL,0,0))    {TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){HWND        hwndBtnPause, hwndBtnQuit, hwndBtnNew, hwndBtnMusic;HWND        hwndEdit, hwndEditscore, hwndEditLine;    HDC         hdc;PAINTSTRUCT ps;static int  speed = 600; //在计时器中用于控制速度static int  num = 0;  static int  puase = 1, misa  = 1; static int  TotalLines = 0; //统计消去的行数static int  TotalScore = 0; //统计总得分int         line = 0; //用来记录每次消去的行数TCHAR       szStr[256], szLines[256] = TEXT("行数: ");TCHAR       szStb[256], szScore[256] = TEXT("分数: ");switch(message){case WM_CREATE: //创建一些子窗口{            hwndBtnPause = CreateWindow(TEXT("button"), TEXT("暂停"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,                      280, 320, 80, 30, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);hwndBtnQuit  = CreateWindow(TEXT("button"), TEXT("离开"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,                      280, 355, 80, 30, hwnd, (HMENU)2, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);hwndBtnNew   = CreateWindow(TEXT("button"), TEXT("新游戏"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,                      280, 390, 80, 30, hwnd, (HMENU)3, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);hwndBtnMusic = CreateWindow(TEXT("button"), TEXT("音乐开"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,                      280, 425, 80, 30, hwnd, (HMENU)7, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);hwndEdit  = CreateWindow(TEXT("edit"), TEXT("第 1 关"), WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER |WS_DISABLED,                      280, 220, 80, 20, hwnd, (HMENU)4, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);hwndEditscore = CreateWindow(TEXT("edit"), TEXT("分数: 0"), WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER | WS_DISABLED,                      280, 250, 80, 20, hwnd, (HMENU)5, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);hwndEditLine = CreateWindow(TEXT("edit"), TEXT("行数: 0"), WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER | WS_DISABLED,                      280, 280, 80, 20, hwnd, (HMENU)6, ((LPCREATESTRUCT)lParam)-> hInstance, NULL);//创建9中颜色画刷            Color[0] = CreateSolidBrush(RGB(0,      0,     0)); //黑色背景画刷Color[1] = CreateSolidBrush(RGB(0,    255,   255));Color[2] = CreateSolidBrush(RGB(73,   213,    73)); Color[3] = CreateSolidBrush(RGB(221,   37,    13));Color[4] = CreateSolidBrush(RGB(216,  232,     0));Color[5] = CreateSolidBrush(RGB(229,  106,    50));Color[6] = CreateSolidBrush(RGB(64,     0,   207));Color[7] = CreateSolidBrush(RGB(166,    0,   218));Color[8] = CreateSolidBrush(RGB(255,   255,  255));srand((unsigned)time(0)); //创建时取随机种子SetTimer(hwnd, 1, speed, NULL);}break;case WM_PAINT:{hdc = BeginPaint(hwnd, &ps); DrawWindow(hdc); //画边框LoadRectangle(hdc); //加载方块if(0 == num) //第一次响应WM_PAINT消息时num为0{Init(); //第一次初始化在WM_PAINT中,以后就不能在WM_PAINT中了Px = Pos.x; //记录此时位置信息,这样就避免了因拖动窗口等刷新客户区时 预览框图形随着Pos.X或Pos.y的自增而移位Py = Pos.y;DrawP(hdc, Pos.dir, Pos.shape, icolor, Px +9, Py +5); //在预览框中画图形PrevShape = rand()%7;                PrevColor = PrevShape +1;DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y);num = 1;}else{DrawP(hdc, Pos.dir, Pos.shape, icolor, Px +9, Py +5); //在预览框中画图形DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y); //在游戏窗口区画上次预览窗口中的图形}EndPaint(hwnd, &ps);}break;   case WM_TIMER:{hdc=GetDC(hwnd);if(Check(Pos.dir, PrevShape, Pos.x, Pos.y +1)){DrawP(hdc, Pos.dir, PrevShape, 0, Pos.x, Pos.y++);DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y);}else{    line = SaveRectangle(hdc, hwnd, Pos.dir, PrevShape, Pos.x, Pos.y);TotalLines += line; itoa(TotalLines, szStr, 10);lstrcat(szLines, szStr);SetWindowText(GetDlgItem(hwnd,6), szLines); //编辑框中填入行数if(1 == line) //判断加多少分{TotalScore += 10;}else if(2 == line){TotalScore += 30;}else if(3 == line){TotalScore += 60;}else if(4 == line){TotalScore += 100;}itoa(TotalScore, szStb, 10);lstrcat(szScore, szStb);SetWindowText(GetDlgItem(hwnd,5), szScore); //编辑框中填入得分if(TotalScore<200)//判断到达第几关,并调速度{SetWindowText(GetDlgItem(hwnd,4), TEXT("第 1 关"));}else if(TotalScore<600){speed = 500;SetTimer(hwnd, 1, speed, NULL);SetWindowText(GetDlgItem(hwnd,4), TEXT("第 2 关"));   }else if(TotalScore<1000){    speed = 450;    SetTimer(hwnd, 1, speed, NULL);    SetWindowText(GetDlgItem(hwnd,4), TEXT("第 3 关"));   }else if(TotalScore<1800){    speed = 400;SetTimer(hwnd, 1, speed, NULL);    SetWindowText(GetDlgItem(hwnd,4), TEXT("第 4 关"));}else if(TotalScore<2800){ speed = 350; SetTimer(hwnd, 1, speed, NULL); SetWindowText(GetDlgItem(hwnd,4), TEXT("第 5 关"));}    else if(TotalScore<5000){ speed = 300; SetTimer(hwnd, 1, speed, NULL); SetWindowText(GetDlgItem(hwnd,4), TEXT("第 6 关"));}else if(TotalScore<7500){ speed = 250; SetTimer(hwnd, 1, speed, NULL); SetWindowText(GetDlgItem(hwnd,4), TEXT("第 7 关"));}    else if(TotalScore<10000){ speed = 200; SetTimer(hwnd, 1, speed, NULL); SetWindowText(GetDlgItem(hwnd,4), TEXT("第 8 关"));}else { speed = 100; SetTimer(hwnd, 1, speed, NULL); SetWindowText(GetDlgItem(hwnd,4), TEXT("第 9 关"));}if(!GameOver()) //判断游戏是否结束,为TRUE时结束{ PrevShape = Pos.shape %7; //保存预览框中图形信息,用于游戏区画下一个图形 PrevColor = PrevShape +1; Init();  Px = Pos.x; //记录此时位置信息,这样就避免了因拖动窗口等刷新客户区时 预览框图形随着Pos.X或Pos.y的自增而移位 Py = Pos.y; InvalidateRect(hwnd, NULL, FALSE);}else{KillTimer(hwnd, 1);MessageBox(NULL,TEXT("游戏结束!"), "", MB_OK);}}    ReleaseDC(hwnd, hdc);}break;case WM_KEYDOWN:{hdc = GetDC(hwnd);switch(wParam){   case 87: //'W'   case VK_UP:   {   if(Check((Pos.dir+1)%4, PrevShape, Pos.x, Pos.y))   {   DrawP(hdc, Pos.dir, PrevShape, 0, Pos.x, Pos.y);   Pos.dir = (Pos.dir+1) % 4;               DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y);   PlaySound(TEXT("wave1"),(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), SND_RESOURCE|SND_ASYNC|SND_NOSTOP);   }     }   break;   case 68: //'D'   case VK_RIGHT:   {   if(Check(Pos.dir, PrevShape, Pos.x+1, Pos.y))   {   DrawP(hdc, Pos.dir, PrevShape, 0, Pos.x++, Pos.y);                   DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y);   }   }   break;   case 65: //'A'   case VK_LEFT:   {   if(Check(Pos.dir, PrevShape, Pos.x-1,Pos.y))   {   DrawP(hdc, Pos.dir, PrevShape, 0, Pos.x--, Pos.y);   DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y);   }   }   break;   case 83: //'S'   case VK_DOWN:   {   if(Check(Pos.dir, PrevShape, Pos.x, Pos.y+1))   {   DrawP(hdc, Pos.dir, PrevShape, 0, Pos.x, Pos.y++);   DrawP(hdc, Pos.dir, PrevShape, PrevColor, Pos.x, Pos.y);   }   else   {   line = SaveRectangle(hdc, hwnd, Pos.dir, PrevShape, Pos.x, Pos.y);               TotalLines += line;   itoa(TotalLines, szStr, 10);   lstrcat(szLines, szStr);   SetWindowText(GetDlgItem(hwnd,6), szLines);   if(1 == line)   {   TotalScore += 10;   }   else if(2 == line)   {   TotalScore += 30;   }   else if(3 == line)   {   TotalScore += 60;   }   else if(4 == line)   {   TotalScore += 100;   }   itoa(TotalScore, szStb, 10);   lstrcat(szScore, szStb);               SetWindowText(GetDlgItem(hwnd,5), szScore);   if(TotalScore<200)//判断到达第几关,并调速度   {   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 1 关"));   }   else if(TotalScore<600)   {   speed = 500;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 2 关"));      }   else if(TotalScore<1000)   {   speed = 450;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 3 关"));      }   else if(TotalScore<1800)   {   speed = 400;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 4 关"));   }   else if(TotalScore<2800)   {   speed = 350;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 5 关"));   }   else if(TotalScore<5000)   {   speed = 300;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 6 关"));   }   else if(TotalScore<7500)   {   speed = 250;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 7 关"));   }   else if(TotalScore<10000)   {   speed = 200;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 8 关"));   }   else    {   speed = 100;   SetTimer(hwnd, 1, speed, NULL);   SetWindowText(GetDlgItem(hwnd,4), TEXT("第 9 关"));   }   if(!GameOver()) //判断游戏是否结束,为TRUE时结束   {   PrevShape = Pos.shape %7; //保存预览框中图形信息,用于游戏区画下一个图形   PrevColor = PrevShape +1;   Init();   Px = Pos.x;               Py = Pos.y;   InvalidateRect(hwnd, NULL, FALSE);   }   else   {   KillTimer(hwnd, 1);   MessageBox(NULL,TEXT("游戏结束!"), "", MB_OK);   }   }   }   break;}ReleaseDC(hwnd, hdc);}break;case WM_COMMAND:{switch(wParam){case 1: //暂停或继续{if(!GameOver()) //判断游戏是否结束,为FALSE时没有结束{if(1 == puase){puase = 0;KillTimer(hwnd, 1);SetWindowText(GetDlgItem(hwnd,1), "继续");}else{puase = 1;SetTimer(hwnd, 1, speed, NULL);SetWindowText(GetDlgItem(hwnd,1), "暂停"); SetFocus(hwnd); //把输入焦点换回到主窗口}}}break;case 2: //是否离开{KillTimer(hwnd, 1);if(IDYES == MessageBox(NULL, TEXT("确定退出游戏?"), "", MB_YESNO)){PostQuitMessage(0);}else{if(!GameOver()) //判断游戏是否结束,为TRUE时结束{SetTimer(hwnd, 1, speed, NULL);    SetFocus(hwnd);}}}break;case 3: //是否开始新游戏{KillTimer(hwnd, 1);if(IDYES == MessageBox(NULL, TEXT("开始新游戏?"), "", MB_YESNO)){ZeroMemory(Rstate,   sizeof(Rstate)); //清空数组,重置一些内容ZeroMemory(Cstate, sizeof(Cstate));TotalLines = 0;                        TotalScore = 0;SetWindowText(GetDlgItem(hwnd,5), TEXT("分数: 0"));SetWindowText(GetDlgItem(hwnd,6), TEXT("行数: 0"));Init();InvalidateRect(hwnd, NULL, TRUE);SetTimer(hwnd, 1, speed, NULL);SetFocus(hwnd);}else{if(!GameOver()) //判断游戏是否结束,为TRUE时结束{SetTimer(hwnd, 1, speed, NULL);    SetFocus(hwnd);}}}break;case 7: //音乐关闭{if(1 == misa){misa = 0;PlaySound(TEXT("wave3"), (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), SND_RESOURCE|SND_ASYNC|SND_LOOP|SND_NOSTOP);SetWindowText(GetDlgItem(hwnd,7), "音乐关");}else{misa = 1;PlaySound(TEXT("wave1"), (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), SND_RESOURCE|SND_ASYNC);SetWindowText(GetDlgItem(hwnd,7), "音乐开");}SetFocus(hwnd); //把输入焦点换回到主窗口}break;case IDM_AUTHOR: //作者{DialogBox((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), MAKEINTRESOURCE(IDD_DIALOG1), NULL, AboutDlgProc);}break;case IDM_DS:{MessageBox(NULL, TEXT("==================\n"                  "W或 ↑: 改变形状\n"                  "A 或 ←: 向左移动\n"  "D 或 →: 向右移动\n"  "S 或 ↓: 向下加速\n"  "==================\n"  "行数多不一定得分多~~\n"  "拼命一次消3、4行吧~~"), TEXT("游戏说明"), MB_OK);}break;default:break;}}break;case WM_DESTROY:{KillTimer(hwnd, 1);PostQuitMessage(0);}break;default:break;}return DefWindowProc(hwnd, message, wParam, lParam);}//初始化void Init(void){  Pos.dir = 0;Pos.shape = rand()%7;    icolor = Pos.shape + 1;Pos.x = 2;Pos.y = 0;}//画方块void Draw(HDC hdc, int x, int y, int sele){    int  screenx = 13 + x *FSIZE; //方块左上角的坐标是x乘方块大小再加上起始位置    int  screeny = 16 + y *FSIZE;    RECT rt;    rt.left   = screenx + 1;    rt.top    = screeny + 1;    rt.right  = screenx + FSIZE;    rt.bottom = screeny + FSIZE;    FillRect(hdc, &rt, Color[sele]); //填充}//画图形void DrawP(HDC hdc, int dir, int shape, int color, int x, int y){int i;for(i=0; i<4; i++){Sx = Rect[shape][dir][i].x + x;Sy = Rect[shape][dir][i].y + y;Draw(hdc, Sx, Sy, color);}}//画边框void DrawWindow(HDC hdc){HBRUSH hBrush;    hBrush = CreateSolidBrush(RGB(0,0,0)); //创黑色色画刷SelectObject(hdc, CreatePen(PS_DOT, 0, RGB(255, 0, 255))); //创建红色画笔,描外边框SelectObject(hdc, hBrush);  Rectangle(hdc, 10, 14, 237, 527); SelectObject(hdc, CreatePen(PS_SOLID, 0, RGB(0, 255, 0))); //创建绿色画笔,描内边框SelectObject(hdc, hBrush);  //将黑色画刷选进设备描述表,用黑色填充图形内部    Rectangle(hdc, 12, 16, 235, 525);SelectObject(hdc, CreatePen(PS_SOLID, 0, RGB(255, 255, 0))); //创建画笔,描预览框SelectObject(hdc, hBrush);      Rectangle(hdc, 260, 110, 380, 185); }BOOL Check(int dir, int shape, int Px, int Py)//检查是否越界,越界返回FALSE,                                                           {                                                        int i, x, y;for(i=0; i<4; i++){x = Rect[shape][dir][i].x + Px;y = Rect[shape][dir][i].y + Py;if(x<0||x>=10 || y>=23 || Rstate[x][y]!=0){return FALSE;}}return TRUE;}//存储落下的方块int SaveRectangle(HDC hdc, HWND hwnd, int dir, int shape, int x, int y){int i, j, line = 0, temp = 0; bool State;for(i=0; i<4; i++){Sx = Rect[shape][dir][i].x + x;Sy = Rect[shape][dir][i].y + y;    Rstate[Sx][Sy] = 1; //存储落下的方块,记录位置Cstate[Sx][Sy] = PrevColor; //记录对应的颜色}for(j=0; j<23; j++) //判断是否有满行,有则用该行的上一行填充该行,以达到消去的目的{for(i=0; i<10; i++){if(Rstate[i][j] !=1 ) //有一个没被占就说明此行未满,跳出内循环,对下一行进行判断{State = false;break;}}if(10 == i && 1 == Rstate[9][j]) //此条件为真时说明该行以满{State = true;    line++; //统计行数if(1 == line) //判断第一个满行时,记录行数{temp = j;}if(line > 1) //当满行数超过1时{for(i=0; i<10; i++) //重绘第一个判断满行的那一行{Draw(hdc, i, temp, 8);}for(i=0; i<10; i++) //重绘剩下的满行的那些行{Draw(hdc, i, j, 8);}    Sleep(200); //PS: 之所以这样我也很郁闷,代码都写成这样了不知道过几个月还能看懂不了。。。}}if(State) //满行时,用该行的上一行填充该行,以达到消去的目的{for(m=j; m>1; m--){for(int n=0; n<10; n++){Rstate[n][m] = Rstate[n][m-1];Cstate[n][m] = Cstate[n][m-1];}}} }//在循环外面if(1 == line) //当仅有一行满行时,就重绘那一行,并播放声音,这样才能看见重绘的效果,没有声音,就看不见重绘的效果,这是为什么?{for(i=0; i<10; i++){Draw(hdc, i, temp, 8);}PlaySound(TEXT("wave2"), (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), SND_RESOURCE|SND_ASYNC|SND_NOSTOP);Sleep(200);}else if(line > 1) //满行数超过1时就播放声音,最好在循环外,保证其只播放一次{PlaySound(TEXT("wave2"), (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), SND_RESOURCE|SND_ASYNC|SND_NOSTOP);}//PS:很乱,为什么重绘和声音播放还是有关系呢。。当开了背景音乐时,仅有一行满行并重绘时,仍然无法看到效果,应该是此时声音无效的原因return line;}//屏幕刷新时加载已经存在的方块void LoadRectangle(HDC hdc) {int i, j;for(i=0; i<10; i++){for(j=0; j<23; j++){if(1 == Rstate[i][j]){ Draw(hdc, i, j, Cstate[i][j]);              }}}}//判断游戏是否结束BOOL GameOver(void){int i, j;BOOL over = FALSE;for(j=0, i=0; i<10; i++){if(1 == Rstate[i][j]) //最上面一行有一个格子被占就返回TRUE,游戏结束{ over = TRUE;break;}}return over;}BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){switch(message){case WM_INITDIALOG:return TRUE;case WM_COMMAND:switch(LOWORD(wParam)){case IDOK:EndDialog(hDlg,0);break;}break;}return FALSE;}

0 0
原创粉丝点击