当前位置:文档之家› C语言编写的俄罗斯方块

C语言编写的俄罗斯方块

用C语言写的一个简单的俄罗斯方块!会用到graphics.h的库,需要自己准备,可以在网上下载EasyX 解决。

下边是源代码(扩展名为.cpp):#include <easyx.h>#include <conio.h>#include <time.h>#define WIDTH 10 // 游戏区宽度#define HEIGHT 22 // 游戏区高度#define UNIT 20 // 每个游戏区单位的实际像素// 定义操作类型enum CMD{CMD_ROTATE, // 方块旋转CMD_LEFT, CMD_RIGHT, CMD_DOWN, // 方块左、右、下移动CMD_SINK, // 方块沉底CMD_QUIT // 退出游戏};// 定义绘制方块的方法enum DRAW{SHOW, // 显示方块CLEAR, // 擦除方块FIX // 固定方块};// 定义七种俄罗斯方块struct BLOCK{WORD dir[4]; // 方块的四个旋转状态COLORREF color; // 方块的颜色} g_Blocks[7] = { {0x0F00, 0x4444, 0x0F00, 0x4444, RED}, // I{0x0660, 0x0660, 0x0660, 0x0660, BLUE}, // 口{0x4460, 0x02E0, 0x0622, 0x0740, MAGENTA}, // L{0x2260, 0x0E20, 0x0644, 0x0470, YELLOW}, // 反L{0x0C60, 0x2640, 0x0C60, 0x2640, CYAN}, // Z{0x0360, 0x4620, 0x0360, 0x4620, GREEN}, // 反Z{0x4E00, 0x4C40, 0x0E40, 0x4640, BROWN}}; // T// 定义当前方块、下一个方块的信息struct BLOCKINFO{byte id; // 方块 IDchar x, y; // 方块在游戏区中的坐标byte dir:2; // 方向} g_CurBlock, g_NextBlock;// 定义游戏区BYTE g_World[WIDTH][HEIGHT] = {0};void Init(); // 初始化游戏void Quit(); // 退出游戏void NewGame(); //开始新游戏void GameOver(); //结束游戏CMD GetCmd(); //获取控制命令void DispatchCmd(CMD _cmd);// 分发控制命令void NewBlock(); //生成新的方块bool CheckBlock(BLOCKINFO _block);// 检测指定方块是否可以放下void DrawUnit(int x, int y, COLORREF c, DRAW _draw); // 画单元方块void DrawBlock(BLOCKINFO _block, DRAW _draw = SHOW); // 画方块void OnRotate(); //旋转方块void OnLeft(); //左移方块void OnRight(); //右移方块void OnDown(); //下移方块void OnSink(); //沉底方块// 主函数void main(){Init();//界面函数CMD c;while(true){c = GetCmd();DispatchCmd(c);// 按退出时,显示对话框咨询用户是否退出if (c == CMD_QUIT){HWND wnd = GetHWnd();if (MessageBox(wnd, _T("您要退出游戏吗?"), _T("提醒"), MB_OKCANCEL | MB_ICONQUESTION)== IDOK)Quit();}}}//界面void Init(){initgraph(640, 480); //初始化文本框宽度、高度srand((unsigned)time(NULL)); //产生随机数setbkmode(TRANSPARENT); // 设置图案填充的背景色为透明// 显示操作说明settextstyle(14, 0, _T("宋体"));outtextxy(20, 330, _T("操作说明"));outtextxy(20, 350, _T("上:旋转"));outtextxy(20, 370, _T("左:左移"));outtextxy(20, 390, _T("右:右移"));outtextxy(20, 410, _T("下:下移"));outtextxy(20, 430, _T("空格:沉底"));outtextxy(20, 450, _T("ESC:退出"));// 设置坐标原点setorigin(220, 20);// 绘制游戏区边界rectangle(-1, -1, WIDTH * UNIT, HEIGHT * UNIT);rectangle((WIDTH + 1) * UNIT - 1, -1, (WIDTH + 5) * UNIT, 4 * UNIT);// 开始新游戏NewGame();}// 退出游戏void Quit(){closegraph();exit(0);}// 开始新游戏void NewGame(){// 清空游戏区setfillcolor(BLACK);//游戏区背景颜色solidrectangle(0, 0, WIDTH * UNIT - 1, HEIGHT * UNIT - 1);ZeroMemory(g_World, WIDTH * HEIGHT);// 生成下一个方块g_NextBlock.id = rand() % 7;g_NextBlock.dir = rand() % 4;g_NextBlock.x = WIDTH + 1;g_NextBlock.y = HEIGHT - 1;// 获取新方块NewBlock();}// 结束游戏void GameOver(){HWND wnd = GetHWnd();if (MessageBox(wnd, _T("游戏结束。

\n您想重新来一局吗?"), _T("游戏结束"), MB_YESNO | MB_ICONQUESTION) == IDYES)NewGame();elseQuit();}// 获取控制命令DWORD m_oldtime;CMD GetCmd(){// 获取控制值while(true){// 如果超时,自动下落一格DWORD newtime = GetTickCount();if (newtime - m_oldtime >= 500){m_oldtime = newtime;return CMD_DOWN;}// 如果有按键,返回按键对应的功能if (kbhit()){switch(getch()){case 'w':case 'W': return CMD_ROTATE;//命令旋转case 'a':case 'A': return CMD_LEFT;//-- 向左case 'd':case 'D': return CMD_RIGHT;//-- 向右case 's':case 'S': return CMD_DOWN;//-- 向下case 27: return CMD_QUIT;//-- 退出case ' ': return CMD_SINK;//-- 沉底case 0:case 0xE0://方向区switch(getch()){case 72: return CMD_ROTATE;case 75: return CMD_LEFT;case 77: return CMD_RIGHT;case 80: return CMD_DOWN;}}}// 延时Sleep(20);}}// 分发控制命令void DispatchCmd(CMD _cmd){switch(_cmd){case CMD_ROTATE: OnRotate(); break;case CMD_LEFT: OnLeft(); break;case CMD_RIGHT: OnRight(); break;case CMD_DOWN: OnDown(); break;case CMD_SINK: OnSink(); break;case CMD_QUIT: break;}}// 生成新的方块void NewBlock(){g_CurBlock.id = g_NextBlock.id,g_NextBlock.id = rand() % 7;g_CurBlock.dir = g_NextBlock.dir, g_NextBlock.dir = rand() % 4;g_CurBlock.x = (WIDTH - 4) / 2;g_CurBlock.y = HEIGHT + 2;// 下移新方块直到有局部显示WORD c = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];while((c & 0xF) == 0){g_CurBlock.y--;c >>= 4;}// 绘制新方块DrawBlock(g_CurBlock);// 绘制下一个方块setfillcolor(BLACK);solidrectangle((WIDTH + 1) * UNIT, 0, (WIDTH + 5) * UNIT - 1, 4 * UNIT - 1);DrawBlock(g_NextBlock);// 设置计时器,用于判断自动下落m_oldtime = GetTickCount();}// 画单元方块void DrawUnit(int x, int y, COLORREF c, DRAW _draw){// 计算单元方块对应的屏幕坐标int left = x * UNIT;int top = (HEIGHT - y - 1) * UNIT;int right = (x + 1) * UNIT - 1;int bottom = (HEIGHT - y) * UNIT - 1;// 画单元方块switch(_draw){case SHOW:// 画普通方块setlinecolor(0x006060);roundrect(left + 1, top + 1, right - 1, bottom - 1, 5, 5);setlinecolor(0x003030);roundrect(left, top, right, bottom, 8, 8);setfillcolor(c);setlinecolor(LIGHTGRAY);fillrectangle(left + 2, top + 2, right - 2, bottom - 2);break;case FIX:// 画固定的方块setfillcolor(RGB(GetRValue(c) * 2 / 3, GetGValue(c) * 2 / 3, GetBValue(c) * 2 / 3));setlinecolor(DARKGRAY);fillrectangle(left + 1, top + 1, right - 1, bottom - 1);break;case CLEAR:// 擦除方块setfillcolor(BLACK);solidrectangle(x * UNIT, (HEIGHT - y - 1) * UNIT, (x + 1) * UNIT - 1, (HEIGHT - y) * UNIT - 1);break;}}// 画方块void DrawBlock(BLOCKINFO _block, DRAW _draw) {WORD b = g_Blocks[_block.id].dir[_block.dir];int x, y;for(int i = 0; i < 16; i++, b <<= 1)if (b & 0x8000){x = _block.x + i % 4;y = _block.y - i / 4;if (y < HEIGHT)DrawUnit(x, y, g_Blocks[_block.id].color, _draw);}}// 检测指定方块是否可以放下bool CheckBlock(BLOCKINFO _block){WORD b = g_Blocks[_block.id].dir[_block.dir];int x, y;for(int i = 0; i < 16; i++, b <<= 1)if (b & 0x8000){x = _block.x + i % 4;y = _block.y - i / 4;if ((x < 0) || (x >= WIDTH) || (y < 0)) return false;if ((y < HEIGHT) && (g_World[x][y]))return false;}return true;}// 旋转方块void OnRotate(){// 获取可以旋转的 x 偏移量int dx;BLOCKINFO tmp = g_CurBlock;tmp.dir++; if (CheckBlock(tmp)) { dx = 0; goto rotate; }tmp.x = g_CurBlock.x - 1; if (CheckBlock(tmp)) { dx = -1; goto rotate; } tmp.x = g_CurBlock.x + 1; if (CheckBlock(tmp)) { dx = 1; goto rotate; } tmp.x = g_CurBlock.x - 2; if (CheckBlock(tmp)) { dx = -2; goto rotate; } tmp.x = g_CurBlock.x + 2; if (CheckBlock(tmp)) { dx = 2; goto rotate; } return;rotate:// 旋转DrawBlock(g_CurBlock, CLEAR);g_CurBlock.dir++;g_CurBlock.x += dx;DrawBlock(g_CurBlock);}// 左移方块void OnLeft(){BLOCKINFO tmp = g_CurBlock;tmp.x--;if (CheckBlock(tmp)){DrawBlock(g_CurBlock, CLEAR);g_CurBlock.x--;DrawBlock(g_CurBlock);}}// 右移方块void OnRight(){BLOCKINFO tmp = g_CurBlock;tmp.x++;if (CheckBlock(tmp)){DrawBlock(g_CurBlock, CLEAR);g_CurBlock.x++;DrawBlock(g_CurBlock);}}// 下移方块void OnDown(){BLOCKINFO tmp = g_CurBlock;tmp.y--;if (CheckBlock(tmp)){DrawBlock(g_CurBlock, CLEAR);g_CurBlock.y--;DrawBlock(g_CurBlock);}elseOnSink(); // 不可下移时,执行“沉底方块”操作}// 沉底方块void OnSink(){int i, x, y;// 连续下移方块DrawBlock(g_CurBlock, CLEAR);BLOCKINFO tmp = g_CurBlock;tmp.y--;while (CheckBlock(tmp)){g_CurBlock.y--;tmp.y--;}DrawBlock(g_CurBlock, FIX);// 固定方块在游戏区WORD b = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];for(i = 0; i < 16; i++, b <<= 1)if (b & 0x8000){if (g_CurBlock.y - i / 4 >= HEIGHT){ // 如果方块的固定位置超出高度,结束游戏GameOver();return;}elseg_World[g_CurBlock.x + i % 4][g_CurBlock.y - i / 4] = 1;}// 检查是否需要消掉行,并标记BYTE remove = 0; // 低 4 位用来标记方块涉及的 4 行是否有消除行为for(y = g_CurBlock.y; y >= max(g_CurBlock.y - 3, 0); y--){i = 0;for(x = 0; x < WIDTH; x++)if (g_World[x][y] == 1)i++;if (i == WIDTH){remove |= (1 << (g_CurBlock.y - y));setfillcolor(LIGHTGREEN);setlinecolor(LIGHTGREEN);setfillstyle(BS_HATCHED,HS_DIAGCROSS);fillrectangle(0, (HEIGHT - y - 1) * UNIT + UNIT / 2 - 5, WIDTH * UNIT - 1, (HEIGHT - y - 1) * UNIT + UNIT / 2 + 5);setfillstyle(BS_SOLID);}}if (remove) // 如果产生整行消除{// 延时 300 毫秒Sleep(300);// 擦掉刚才标记的行IMAGE img;for(i = 0; i < 4; i++, remove >>= 1){if (remove & 1){for(y = g_CurBlock.y - i + 1; y < HEIGHT; y++)for(x = 0; x < WIDTH; x++){g_World[x][y - 1] = g_World[x][y];g_World[x][y] = 0;}getimage(&img, 0, 0, WIDTH * UNIT, (HEIGHT - (g_CurBlock.y - i + 1)) * UNIT);putimage(0, UNIT, &img);}}}// 产生新方块NewBlock(); }。

相关主题