CodeBus

分享代码,一起进步~

游戏:奔跑的火柴人

这是一款以火柴人为人物的小游戏,人物通过操作躲过各种障碍物,当人物撞到障碍物则游戏结束。 操作说明:W—跳跃,S—滚动 游戏执行效果: 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:星QQ:453496034邮箱:liluxing1993@qq.com

游戏:种地要浇水(创意源自《金庸无双》)

游戏规则 填补水渠使每块田地都被灌溉。方向键选择,空格确定。 特技(耗金币): 重置:R 键 顺时针旋转:S 键 逆时针旋转:N 键 跳过一个:T 键 (具体金币盈亏细则,可以在游戏中按 H 键查看)。 注:游戏创意源自《金庸无双》。 游戏运行截图 源代码下载 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:i92076https://www.baidu.com/p/i92076

游戏:大丰收(含有 VC6 游戏源码 和 完整论文)

喜庆丰收,这是一款锻炼玩家反应能力的游戏,游戏中玩家通过控制上和左右键控制可爱的小猴子在地面上跳跃或者是平行移动,来接取天空中飘落的水果。接到不同的水果会得到不同的分数,桃子 10 分,西瓜 20 分,菠萝 30 分,接到炸弹扣 40 分,接不到水果也会扣 10 分,当扣分达到 500 游戏结束(扣分只计算没接到水果),当得分到达 500 会进入下一关,右侧会显示最高得分玩家的用户名和分数,游戏中可以点击暂停键,暂停,再次点击游戏开始,按空格键也可以暂停游戏,在按任意键开始,点击结束会关闭游戏,不保存游戏信息,正常游戏结束,会将游戏信息保存。 游戏运行截图如下: 游戏附带有完整的 VC6 源代码,以及完整的游戏资源(图片和音效),并附有原作者写的论文。 全部文档请【点击这里下载】。 作者:杨盼QQ:745509409指导教师:蔡越江

青蛙过河小游戏v1.0

作者感想 这是一个很典型的游戏,很多程序使用的也是这种结构,制作多个元件同时的运动。还有如何用光栅获得透明背景。希望我的小作品能抛砖引玉,给大家一点启发! 待扩展的功能 难度 更多关卡 商店 分数排行榜 岸上的障碍 背景音乐 音效 鼠标控制 时间限制 等 游戏规则 WSAD控制,ESC退到主界面,再按则退出。 木板间隔是随机的。 生命归零时游戏结束。 渡河会导致1条河道速度+2。 死亡会导致所有河道速度-1。 青蛙出界或落水算死亡。 不会在第一道出界。 积分的算法是四条河道速度相加。 金币留给以后扩展程序。 源码说明 图片放在res文件夹里,请把res和frogger.exe放在同一个文件夹里。 关于各种元件的代码分别写在以它们命名的cpp里。 几乎所有能改的常量都定义在constant.h里。 运行截图 完整源代码 完整的游戏 VC++ 源代码:<点击这里下载> 作者:P_S_I

扔香蕉的大猩猩(怀旧)

又是一个怀旧的游戏,让我想起了以前学习编程的时候。 这个游戏模仿的微软在 20 多年前的一个小游戏,不知道谁也有印象呢?图片都是从原来的游戏中抓图弄出来的,颜色也是从原游戏抓图中取色设置的,应该和原来的风格很像。 你的任务是用香蕉击中你的对手。 你可以通过鼠标调整投掷香蕉的角度和力度,香蕉会受重力加速度的影响。同时,请注意屏幕底部表示风力的箭头,香蕉同样会受风力影响。风力的箭头越长,表示风力越强。还有,周围的楼宇会阻挡你的香蕉。 游戏运行效果如下: 游戏源代码如下(注意,除了以下代码,还需要两个图片文件,在底部的压缩包里面有): // 程序名称:扔香蕉的大猩猩 // 编译环境:Visual C++ 6.0 / 2010,EasyX_20130130(beta) // 作  者:yangw80 <yw80@qq.com> // 最后修改:2013-3-3 (2012-9-23) // 本游戏是仿照微软很古老的一个游戏写的。 // 游戏说明:你的任务是使用香蕉击中你的对手。 //      可以调整扔的角度和力度,同时香蕉还受风速、重力加速度和楼宇的影响。 // #include <graphics.h> #include <stdio.h> #include <conio.h> #include <time.h> #include <math.h> // 定义常量 #define PI 3.1415926535 // 圆周率 #define SCRWIDTH 640 // 屏幕宽度 #define SCRHEIGHT 480 // 屏幕高度 #define GRAVITY 9.8 // 重力加速度 #define BACKATTR BLUE // 背景的颜色 #define OBJECTCOLOR 0x55AAFF // 对手的颜色 #define EXPLOSIONCOLOR 0x5500FF // 爆炸的颜色 #define SUNATTR 0x00FFFF // 太阳的颜色 #define SUNHEIGHT 40 // 太阳的高度 #define SUNHAPPY true // 太阳高兴 #define SUNSHOCK false // 太阳受惊 // 全局变量 IMAGE g_imgBanana[4]; // 香蕉图片 IMAGE g_imgGorD; // 大猩猩(双手放下) IMAGE g_imgGorL; // 大猩猩(左边的手抬起) IMAGE g_imgGorR; // 大猩猩(右边的手抬起) POINT g_ptGorilla[2]; // 两个游戏者的位置 int g_iLastBuilding; // 最后一栋楼的编号 int g_iWind; // 风力 bool g_bSunHit; // 是否击中太阳 // 函数定义 void Init(); // 初始化 void Intro(); // 游戏介绍 void PlayGame(TCHAR *player1, TCHAR *player2); // 主游戏函数 void MakeCityScape(POINT *aryBCoor); // 创建随机的游戏场景 void PlaceGorillas (POINT *aryBCoor); // 将游戏者放到楼宇顶端 void DoSun(bool smile); // 绘制太阳 bool DoShot(int idPlayer, int x, int y, int* win); // 接收游戏者输入,实现扔香蕉攻击对方 int PlotShot(int startX, int startY, double angle, int velocity, int idPlayer); // 进行香蕉攻击,使香蕉划过屏幕 void DrawBanana(int x, int y, int r, bool d); // 绘制香蕉 void DoExplosion(int x, int y); // 香蕉攻击后的爆炸效果 int ExplodeGorilla(int x, int y); // 游戏者死亡后爆炸 void VictoryDance(int idPlayer); // 绘制跳舞的大猩猩(胜利后执行) // 主函数 void main() { Init(); Intro(); PlayGame(_T("Player 1"), _T("Player 2")); } // 初始化变量 void Init() { initgraph(SCRWIDTH, SCRHEIGHT); // 创建绘图窗口 // 初始化香蕉图案 IMAGE tmp; loadimage(&tmp, _T("GIF"), _T("Banana.gif")); SetWorkingImage(&tmp); getimage(&g_imgBanana[0], 0, 0, 9, 7); getimage(&g_imgBanana[1], 9, 0, 9, 7); getimage(&g_imgBanana[2], 18, 0, 9, 7); getimage(&g_imgBanana[3], 27, 0, 9, 7); // 初始化大猩猩图案 loadimage(&tmp, _T("GIF"), _T("Gorilla.gif"), 0, 0, true); SetWorkingImage(&tmp); getimage(&g_imgGorD, 0, 0, 30, 30); getimage(&g_imgGorL, 30, 0, 30, 30); getimage(&g_imgGorR, 60, 0, 30, 30); SetWorkingImage(NULL); } // 显示游戏介绍 void Intro() { setfont(24, 0, _T("宋体")); // 在屏幕中央输出字符串 RECT r = {0, 40, 640, 80}; drawtext(_T("扔香蕉的大猩猩"), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE); setfont(16, 0, _T("System")); r.top = 120; r.bottom = 480; drawtext(_T("这个游戏模仿的微软在 20 多年前的一个小游戏,\n不知道谁也有印象呢?\n\n") _T("你的任务是用香蕉击中你的对手。\n你可以通过鼠标调整投掷香蕉的角度和力度,\n") _T("香蕉会受重力加速度的影响。\n同时,请注意屏幕底部表示风力的箭头,") _T("香蕉同样会受风力影响。\n风力的箭头越长,表示风力越强。\n") _T("还有,周围的楼宇会阻挡你的香蕉。\n"), &r, DT_CENTER | DT_VCENTER); r.top = 400; drawtext(_T("按任意键继续"), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE); _getch(); } // 主游戏函数 // 参数: // player1, player2:游戏者名称 void PlayGame(TCHAR *player1, TCHAR *player2) { POINT aryBCoor[31]; // 楼宇群的坐标 int aryScore[2] = {0, 0}; // 两个游戏者的得分 TCHAR sScore[20]; // 保存得分的字符串 int player = 0; // 攻击者 setbkcolor(BACKATTR); while(true) { cleardevice(); srand((unsigned int)time(NULL)); MakeCityScape(aryBCoor); PlaceGorillas(aryBCoor); DoSun(SUNHAPPY); bool bHit = false; while(bHit == false) { setcolor(WHITE); RECT r = {0, 0, SCRWIDTH, 20}; drawtext(player1, &r, DT_LEFT | DT_SINGLELINE); drawtext(player2, &r, DT_RIGHT | DT_SINGLELINE); r.top = SCRHEIGHT - 40; r.bottom = SCRHEIGHT - 20; _stprintf(sScore, _T("%d >Score< %d"), aryScore[0], aryScore[1]); drawtext(sScore, &r, DT_CENTER | DT_SINGLELINE); int win; // 进行攻击。击中任意游戏者即返回 true。同时,更新 win 为胜利者 bHit = DoShot(player, g_ptGorilla[player].x, g_ptGorilla[player].y, &win); // 如果太阳被击中,重绘太阳 if (g_bSunHit) DoSun(SUNHAPPY); // 如果击中对手,更新分数 if (bHit == true) aryScore[win]++; // 交替攻击 player = 1 - player; Sleep(100); } Sleep(1000); }; } // 创建随机的游戏场景 // 参数: // aryBCoor[]:存储每一栋楼的左上角坐标 void MakeCityScape(POINT *aryBCoor) { int x = -10; // 设置随机的楼群倾斜的趋势 int slope = rand() % 6; int iNewHt; // 新楼的高度 switch(slope) { case 0: iNewHt = 15; break; // 逐渐升高 case 1: iNewHt = 130; break; // 逐渐降低 case 2: case 3: case 4: iNewHt = 15; break; // 倒 "V" 型(比较常见) case 5: iNewHt = 130; break; // "V" 型 } int iBottomLine = 465; // 建筑的最低端 int iHtInc = 10; // 高度增加值 int iDefBWidth = 37; // 默认的建筑宽度 int iRandomHeight = 120; // 随机的高度差异 int iWWidth = 3; // 窗户宽度 int iWHeight = 6; // 窗户高度 int iWDifV = 15; // 窗户的垂直间距 int iWDifH = 10; // 窗户的水平间距 int iCurBuilding = 0; do { switch(slope) { case 0: iNewHt += iHtInc; break; case 1: iNewHt -= iHtInc; break; case 2: case 3: case 4: if (x > SCRWIDTH / 2) iNewHt -= 2 * iHtInc; else iNewHt += 2 * iHtInc; break; case 5: if (x > SCRWIDTH / 2) iNewHt += 2 * iHtInc; else iNewHt -= 2 * iHtInc; break; } // 设置楼宇宽度,并检查是否超出屏幕 int iBWidth = iDefBWidth + rand() % iDefBWidth; // 设置楼宇高度,并检查楼宇是否超出屏幕下方 int iBHeight = iNewHt + rand() % iRandomHeight; if (iBHeight < iHtInc) iBHeight = iHtInc; // 检查楼宇是否太高 if (iBottomLine - iBHeight <= 25) iBHeight = 20; // 保存楼的坐标 aryBCoor[iCurBuilding].x = x; aryBCoor[iCurBuilding].y = iBottomLine - iBHeight; // 绘制楼宇 COLORREF aryBuildingColor[3] = {CYAN, LIGHTGRAY, RED}; // 定义楼宇的三种颜色 int colorID = rand() % 3; setcolor(BACKATTR); rectangle(x - 1, iBottomLine + 1, x + iBWidth + 1, iBottomLine - iBHeight - 1); setfillcolor(aryBuildingColor[colorID]); bar(x, iBottomLine, x + iBWidth, iBottomLine - iBHeight); // 绘制窗户 int c = x + 3; do { for(int i = iBHeight - 3; i >= 7; i -= iWDifV) { int winColor; if (rand() % 4 == 0) winColor = DARKGRAY; else winColor = YELLOW; setfillcolor(winColor); bar(c, iBottomLine - i, c + iWWidth, iBottomLine - i + iWHeight); } c += iWDifH; } while(c < x + iBWidth - 3); x += iBWidth + 2; iCurBuilding++; } while(x < SCRWIDTH - 1); g_iLastBuilding = iCurBuilding - 1; // 保存最后一栋楼的编号 // 设置随机风力 g_iWind = rand() % 61 - 30; // 绘制风向箭头 if (g_iWind != 0) { int windLine = g_iWind * 3 * (SCRWIDTH / 320); setcolor(EXPLOSIONCOLOR); int arrowDir = (g_iWind > 0) ? -2 : 2; line(SCRWIDTH / 2, SCRHEIGHT - 5, SCRWIDTH / 2 + windLine, SCRHEIGHT - 5); line(SCRWIDTH / 2 + windLine, SCRHEIGHT - 5, SCRWIDTH / 2 + windLine + arrowDir, SCRHEIGHT - 5 - 2); line(SCRWIDTH / 2 + windLine, SCRHEIGHT - 5, SCRWIDTH / 2 + windLine + arrowDir, SCRHEIGHT - 5 + 2); } } // 将游戏者放到楼宇顶端(从边缘数第二个或第三个楼宇上) // 参数: // aryBCoor[]:楼宇数组。保存每栋楼的左上角坐标 void PlaceGorillas(POINT *aryBCoor) { for (int i = 0; i <= 1; i++) { int iBNum = (i == 0) ? rand() % 2 + 1 : g_iLastBuilding - 1 - rand() % 2; int iBWidth = aryBCoor[iBNum + 1].x - aryBCoor[iBNum].x; g_ptGorilla[i].x = aryBCoor[iBNum].x + iBWidth / 2 - g_imgGorD.width / 2; g_ptGorilla[i].y = aryBCoor[iBNum].y - g_imgGorD.height; putimage(g_ptGorilla[i].x, g_ptGorilla[i].y, &g_imgGorD); } } // 绘制太阳 // 参数: // smile:太阳是否微笑 void DoSun(bool smile) { // 设置太阳的位置 int x = SCRWIDTH / 2; int y = SUNHEIGHT - 15; // 绘制太阳 // 脸 setcolor(SUNATTR); setfillcolor(SUNATTR); fillcircle(x, y, 12); // 光芒 for (double a = 0; a < PI * 2; a += PI / 8) line(x, y, int(x + cos(a) * 20 + 0.5), int(y + sin(a) * 16 + 0.5)); // 嘴 setcolor(BACKATTR); setfillcolor(BACKATTR); if (smile) // 绘制笑脸 arc(x - 8, y - 8, x + 8, y + 8, (210 * PI / 180), (330 * PI / 180)); else // 绘制受惊表情("o" 型嘴) fillcircle(x, y + 5, 3); // 眼睛 fillcircle(x - 3, y - 2, 1); fillcircle(x + 3, y - 2, 1); } // 接收游戏者输入,实现扔香蕉攻击对方 // 参数: // idPlayer:游戏者(准备扔香蕉的) // x, y:游戏者的位置 bool DoShot(int idPlayer, int x, int y, int *win) { // 清空鼠标消息缓冲区 FlushMouseMsgBuffer(); // 攻击的起始位置 int startx = x + (idPlayer == 1 ? g_imgGorD.width : 0); int starty = y; // 角度辅助线的位置 int mx = startx, my = starty - 90; int oldmx = mx, oldmy = my; double angle = PI / 2; // 投掷角度 int velocity = 2; // 投掷力度 setwritemode(R2_XORPEN); setcolor(RED); line(startx, starty, mx, my); // 鼠标输入攻击角度 MOUSEMSG msg; while(true) { msg = GetMouseMsg(); if (msg.uMsg == WM_MOUSEMOVE) { if (msg.y > y) { mx = startx + (msg.x > startx ? 90 : -90); my = starty; angle = msg.x > startx ? 0 : PI; } else if (msg.x != startx) { angle = atan(double(starty - msg.y) / (msg.x - startx)); if (angle < 0) angle += PI; mx = startx + int(cos(angle) * 90 + 0.5); my = starty - int(sin(angle) * 90 + 0.5); } else { mx = msg.x; my = y - 90; angle = PI / 2; } line(startx, starty, oldmx, oldmy); line(startx, starty, mx, my); oldmx = mx; oldmy = my; } else if (msg.uMsg == WM_LBUTTONDOWN) break; } line(startx, starty, oldmx, oldmy); // 鼠标输入攻击力度 setlinestyle(PS_SOLID, NULL, 8); oldmx = mx = startx + int(cos(angle) * velocity + 0.5); oldmy = my = starty - int(sin(angle) * velocity + 0.5); line(startx, starty, mx, my); while(true) { if (MouseHit()) { msg = GetMouseMsg(); if (msg.uMsg == WM_LBUTTONUP) break; } mx = startx + int(cos(angle) * velocity + 0.5); my = starty - int(sin(angle) * velocity + 0.5); line(startx, starty, oldmx, oldmy); line(startx, starty, mx, my); oldmx = mx; oldmy = my; if (++velocity > 90) velocity = 2; Sleep(20); } velocity *= 2; // 力度扩大一倍 line(startx, starty, oldmx, oldmy); // 恢复设置 setlinestyle(PS_SOLID, NULL, 1); setwritemode(R2_COPYPEN); // 实施攻击 g_bSunHit = false; int iPlayerHit = PlotShot(x, y, angle, velocity, idPlayer); // 攻击结果 if (iPlayerHit == -1) { *win = -1; return false; } else { *win = (iPlayerHit == idPlayer) ? 1 - idPlayer : idPlayer; VictoryDance(*win); return true; } } // 进行香蕉攻击,使香蕉划过屏幕 // 参数: // startX, startY:游戏者(扔香蕉的)的坐标 // angle:扔出的方向(弧度) // velocity:扔出的力度 // idPlayer:游戏者(扔香蕉的) int PlotShot(int startX, int startY, double angle, int velocity, int idPlayer) { // 投掷力量在 x、y 方向上的分量 double initXVel = cos(angle) * velocity; double initYVel = sin(angle) * velocity; double x, y; double oldx = startX; double oldy = startY; // 绘制游戏者(投掷动作) putimage(startX, startY, idPlayer == 0 ? &g_imgGorL : &g_imgGorR); Sleep(100); // 绘制游戏者(站立动作) putimage(startX, startY, &g_imgGorD); bool bImpact = false; // 是否碰撞 bool bShotInSun = false; // 是否击中太阳 bool bOnScreen = true; // 香蕉是否在屏幕上 int iPlayerHit = -1; // 是否击中对手(-1:未击中;0、1:被击中者的 ID) bool bNeedErase = false; // 是否需要擦掉旧香蕉 POINT look[4]; // 碰撞检测的位置(香蕉中心上下左右四个边的中点) look[2].x = 0; look[3].x = g_imgBanana[0].width - 1; look[0].x = look[1].x = look[3].x / 2; look[0].y = 0; look[1].y = g_imgBanana[0].height - 1; look[2].y = look[3].y = look[1].y / 2; int startXPos = startX; int startYPos = startY - g_imgBanana[0].height; if (idPlayer == 1) startXPos = startXPos + g_imgGorD.width - g_imgBanana[0].width; int pointColor; int rot; double t = 0; while(!bImpact && bOnScreen) { // 擦掉旧香蕉 if (bNeedErase) { bNeedErase = false; DrawBanana(int(oldx + 0.5), int(oldy + 0.5), -1, false); } x = startXPos + (initXVel * t) + (g_iWind / 5.0 * t * t); y = startYPos + (-1 * (initYVel * t) + (GRAVITY * t * t)); if ((x >= SCRWIDTH - 10) || (x <= 3) || (y >= SCRHEIGHT - 3)) bOnScreen = false; if (bOnScreen && y > 0) { // 检测是否击中(对香蕉中心上下左右四个边的中点做检测) for (int i = 0; i < 4; i ++) { pointColor = getpixel(int(x + look[i].x + 0.5), int(y + look[i].y + 0.5)); if (pointColor == BACKATTR || pointColor == WHITE) // 目标是背景色或白色字幕,未击中 { bImpact = false; if (bShotInSun == true && (abs(SCRWIDTH / 2 - int(x)) > 20 || y > SUNHEIGHT)) bShotInSun = false; } else if (pointColor == SUNATTR && y < SUNHEIGHT) // 击中太阳 { if (!g_bSunHit) DoSun(SUNSHOCK); g_bSunHit = true; bShotInSun = true; } else bImpact = true; if (bImpact) break; } if (!bShotInSun && !bImpact) { // 绘制香蕉 rot = int(t * 10) % 4; DrawBanana(int(x + 0.5), int(y + 0.5), rot, true); bNeedErase = true; } oldx = x; oldy = y; } t += 0.1; Sleep(50); } if (pointColor != OBJECTCOLOR && bImpact) DoExplosion(int(x + g_imgBanana[0].width / 2 + 0.5), int(y + g_imgBanana[0].height / 2 + 0.5)); else if (pointColor == OBJECTCOLOR) iPlayerHit = ExplodeGorilla(int(x + 0.5), int(y + 0.5)); return iPlayerHit; } // 绘制香蕉 // 参数: // x, y:香蕉的位置 // r:香蕉的旋转位置 // d:绘制还是擦除(true:绘制;false:擦除) void DrawBanana(int x, int y, int r, bool d) { static IMAGE oldimg; if (d) { getimage(&oldimg, x, y, g_imgBanana[0].width, g_imgBanana[0].height); putimage(x, y, &g_imgBanana[r]); } else putimage(x, y, &oldimg); } // 香蕉攻击后的爆炸效果 // 参数: // x, y:爆炸的位置 void DoExplosion(int x, int y) { int r = 10; int i; setcolor(EXPLOSIONCOLOR); for (i = 0; i <= r; i++) { circle(x, y, i); Sleep(16); } setcolor(BACKATTR); for (i = r; i >= 0; i--) { circle(x, y, i); Sleep(16); } setfillcolor(BACKATTR); fillcircle(x, y, r); } // 游戏者死亡后爆炸 // 参数: // x, y:攻击的位置 int ExplodeGorilla (int x, int y) { int iPlayerHit = (x < SCRWIDTH / 2) ? 0 : 1; int iPlayerX = g_ptGorilla[iPlayerHit].x + g_imgGorD.width / 2; int iPlayerY = g_ptGorilla[iPlayerHit].y + g_imgGorD.height / 2; int i; setcolor(EXPLOSIONCOLOR); for (i = 1; i <= 10; i++) { circle(x, y, i); Sleep(10); } for (i = 1; i <= 16; i++) { circle(iPlayerX, iPlayerY + 11, i); Sleep(10); } for (i = 1; i <= 32; i++) { setcolor((i % 2 == 0) ? 0x54A8FC : 0x5400FC); circle(iPlayerX, iPlayerY, i); Sleep(10); } for (i = 48; i >= 1; i--) { setcolor(BACKATTR); circle(iPlayerX, iPlayerY, i); Sleep(10); } fillcircle(iPlayerX, iPlayerY, 48); return iPlayerHit; } // 绘制跳舞的大猩猩(胜利后执行) // 参数: // idPlayer:游戏者编号 void VictoryDance(int idPlayer) { for (int i = 0; i < 4; i++) { putimage(g_ptGorilla[idPlayer].x, g_ptGorilla[idPlayer].y, &g_imgGorL); Sleep(200); putimage(g_ptGorilla[idPlayer].x, g_ptGorilla[idPlayer].y, &g_imgGorR); Sleep(200); } } 完整的源代码和图片请【点击这里下载】。

RPG 游戏:新精灵

这是一个 RPG 游戏,是作者树之根在暑假写的。 游戏运行截图如下: 源代码太长了,有 7000 多行,所以,这里直接提供代码打包下载: 下载:新精灵 作者:树之根

贪吃蛇游戏的双人对战版

这是贪吃蛇游戏的双人对战版。 游戏双方分别控制蓝色和红色两条小蛇的前进,碰壁或咬到蛇身体算输。 这个对战版的贪吃蛇游戏网上有不少源代码,这个代码的特点就是为两个游戏者分别增加了命令队列,以实现更舒服的控制。 完整的游戏源代码如下: /////////////////////////////////////////////////// // 程序名称:贪吃蛇游戏的双人对战版 // 编译环境:Visual C++ 6.0 / 2010,EasyX_20130322(beta) // 作  者:yangw80 <yw80@qq.com> // 最后修改:2012-7-23 // #include <graphics.h> #include <conio.h> #include <time.h> #include <queue> using namespace std; #define WIDTH 64 // 游戏区域网格宽度 #define HEIGHT 48 // 游戏区域网格高度 #define ITEMSIZE 10 // 游戏元素大小 #define CMD_A_UP 0x1 // 控制命令:游戏者 A 向上 #define CMD_A_DOWN 0x2 // 控制命令:游戏者 A 向下 #define CMD_A_LEFT 0x4 // 控制命令:游戏者 A 向左 #define CMD_A_RIGHT 0x8 // 控制命令:游戏者 A 向右 #define CMD_B_UP 0x10 // 控制命令:游戏者 B 向上 #define CMD_B_DOWN 0x20 // 控制命令:游戏者 B 向下 #define CMD_B_LEFT 0x40 // 控制命令:游戏者 B 向左 #define CMD_B_RIGHT 0x80 // 控制命令:游戏者 B 向右 #define CMD_QUIT 0x100 // 控制命令:退出游戏 // 定义游戏元素 enum ITEM { EMPTY = 0, WALL, PLAYER_A, PLAYER_B, PLAYER_DEAD, PLAYER_A_NEXT, PLAYER_B_NEXT }; // 全局变量 ITEM g_world[WIDTH][HEIGHT]; // 保存游戏区 POINT g_player_a; // 游戏者 A 的坐标 POINT g_player_b; // 游戏者 B 的坐标 POINT g_offset_a; // 游戏者 A 的移动偏移方向 POINT g_offset_b; // 游戏者 B 的移动偏移方向 // 绘制游戏元素 void DrawItem(int x, int y, ITEM item) { switch(item) { case EMPTY: setfillcolor(BLACK); break; case WALL: setfillcolor(LIGHTGRAY); break; case PLAYER_A: setfillcolor(BLUE); break; case PLAYER_B: setfillcolor(RED); break; case PLAYER_DEAD: setfillcolor(MAGENTA); break; } bar(x * ITEMSIZE + 1, y * ITEMSIZE + 1, (x + 1) * ITEMSIZE - 2, (y + 1) * ITEMSIZE - 2); g_world[x][y] = item; } // 初始化游戏 void init() { int x, y; // 绘制墙壁 for(x = 0; x < WIDTH; x++) { DrawItem(x, 0, WALL); DrawItem(x, HEIGHT - 1, WALL); } for(y = 1; y < HEIGHT - 1; y++) { DrawItem(0, y, WALL); DrawItem(WIDTH - 1, y, WALL); } // 绘制游戏区域 for (x = 1; x < WIDTH - 1; x++) for (y = 1; y < HEIGHT - 1; y++) DrawItem(x, y, EMPTY); // 随机产生两个游戏者的位置(至少间隔 5 格) do { g_player_a.x = rand() % (WIDTH - 6) + 3; g_player_a.y = rand() % (HEIGHT - 6) + 3; g_player_b.x = rand() % (WIDTH - 6) + 3; g_player_b.y = rand() % (HEIGHT - 6) + 3; }while ( (g_player_b.x - g_player_a.x) * (g_player_b.x - g_player_a.x) + (g_player_b.y - g_player_a.y) * (g_player_b.y - g_player_b.x) <= 25); // 画出两个游戏者的位置 DrawItem(g_player_a.x, g_player_a.y, PLAYER_A); DrawItem(g_player_b.x, g_player_b.y, PLAYER_B); // 随机产生两个游戏者的移动方向 // 该方法的原理详见:http://www.easyx.cn/skills/View.aspx?id=115 int n; n = (rand() % 4) * 2 + 1; g_offset_a.x = n / 3 - 1; g_offset_a.y = n % 3 - 1; n = (rand() % 4) * 2 + 1; g_offset_b.x = n / 3 - 1; g_offset_b.y = n % 3 - 1; // 绘制 Player A 空心方块提示移动方向 int tx = g_player_a.x + g_offset_a.x; int ty = g_player_a.y + g_offset_a.y; setcolor(BLUE); rectangle(tx * ITEMSIZE + 1, ty * ITEMSIZE + 1, (tx + 1) * ITEMSIZE - 2, (ty + 1) * ITEMSIZE - 2); // 绘制 Player B 空心方块提示移动方向 tx = g_player_b.x + g_offset_b.x; ty = g_player_b.y + g_offset_b.y; setcolor(RED); rectangle(tx * ITEMSIZE + 1, ty * ITEMSIZE + 1, (tx + 1) * ITEMSIZE - 2, (ty + 1) * ITEMSIZE - 2); // 按确定开始游戏 MessageBox(GetHWnd(), _T("对战贪吃蛇 游戏说明:\n\n") \ _T("游戏目标:两条蛇,先碰到墙壁或碰到任何蛇的身体就算输。\n") \ _T("Player A 使用 A S D W 控制蓝色小蛇移动方向。\n") \ _T("Player B 使用上下左右控制红色小蛇移动方向。\n\n") \ _T("点“确定”按钮开始游戏。"), _T("游戏说明"), MB_OK | MB_ICONINFORMATION); } // 获取用户命令 int GetCmd() { // 定义两个用户的命令队列 static queue<int> PLAYER_A_CMD; static queue<int> PLAYER_B_CMD; // 定义每次返回的命令 int cmd = 0; // 处理按键 while(_kbhit()) { switch(_getch()) { case 27: cmd = CMD_QUIT; break; case 'W': case 'w': if (PLAYER_A_CMD.size() < 16) PLAYER_A_CMD.push(CMD_A_UP); break; case 'S': case 's': if (PLAYER_A_CMD.size() < 16) PLAYER_A_CMD.push(CMD_A_DOWN); break; case 'A': case 'a': if (PLAYER_A_CMD.size() < 16) PLAYER_A_CMD.push(CMD_A_LEFT); break; case 'D': case 'd': if (PLAYER_A_CMD.size() < 16) PLAYER_A_CMD.push(CMD_A_RIGHT); break; case 0 : case 0xE0: switch(_getch()) { case 72: if (PLAYER_B_CMD.size() < 16) PLAYER_B_CMD.push(CMD_B_UP); break; case 80: if (PLAYER_B_CMD.size() < 16) PLAYER_B_CMD.push(CMD_B_DOWN); break; case 75: if (PLAYER_B_CMD.size() < 16) PLAYER_B_CMD.push(CMD_B_LEFT); break; case 77: if (PLAYER_B_CMD.size() < 16) PLAYER_B_CMD.push(CMD_B_RIGHT); break; } } } // 读取 Player A 的命令 int c = 0; while(!PLAYER_A_CMD.empty()) { c = PLAYER_A_CMD.front(); PLAYER_A_CMD.pop(); if ((c == CMD_A_UP || c == CMD_A_DOWN) && g_offset_a.x != 0) break; if ((c == CMD_A_LEFT || c == CMD_A_RIGHT) && g_offset_a.y != 0) break; } if (c != 0) cmd |= c; // 读取 Player B 的命令 c = 0; while(!PLAYER_B_CMD.empty()) { c = PLAYER_B_CMD.front(); PLAYER_B_CMD.pop(); if ((c == CMD_B_UP || c == CMD_B_DOWN) && g_offset_b.x != 0) break; if ((c == CMD_B_LEFT || c == CMD_B_RIGHT) && g_offset_b.y != 0) break; } if (c != 0) cmd |= c; // 返回命令 return cmd; } // 处理命令 bool DealCmd(int cmd) { if ((cmd & CMD_A_UP) && g_offset_a.x != 0) { g_offset_a.x = 0; g_offset_a.y = -1; } if ((cmd & CMD_A_DOWN) && g_offset_a.x != 0) { g_offset_a.x = 0; g_offset_a.y = 1; } if ((cmd & CMD_A_LEFT) && g_offset_a.y != 0) { g_offset_a.x = -1; g_offset_a.y = 0; } if ((cmd & CMD_A_RIGHT) && g_offset_a.y != 0) { g_offset_a.x = 1; g_offset_a.y = 0; } if ((cmd & CMD_B_UP) && g_offset_b.x != 0) { g_offset_b.x = 0; g_offset_b.y = -1; } if ((cmd & CMD_B_DOWN) && g_offset_b.x != 0) { g_offset_b.x = 0; g_offset_b.y = 1; } if ((cmd & CMD_B_LEFT) && g_offset_b.y != 0) { g_offset_b.x = -1; g_offset_b.y = 0; } if ((cmd & CMD_B_RIGHT) && g_offset_b.y != 0) { g_offset_b.x = 1; g_offset_b.y = 0; } if (cmd & CMD_QUIT) if (MessageBox(GetHWnd(), _T("您要退出游戏吗?"), _T("游戏暂停"), MB_OKCANCEL) == IDOK) return false; return true; } // 处理游戏 bool DealGame() { // Player A、B 前进 g_player_a.x += g_offset_a.x; g_player_a.y += g_offset_a.y; g_player_b.x += g_offset_b.x; g_player_b.y += g_offset_b.y; // 判断 Player A、B 的生死状态 bool dead_a = false, dead_b = false, dead_ab = false; if (g_player_a.x == g_player_b.x && g_player_a.y == g_player_b.y) { DrawItem(g_player_a.x, g_player_a.y, PLAYER_DEAD); dead_ab = true; } else if (g_world[g_player_a.x][g_player_a.y] != EMPTY) { DrawItem(g_player_a.x, g_player_a.y, PLAYER_DEAD); dead_a = true; } else if (g_world[g_player_b.x][g_player_b.y] != EMPTY) { DrawItem(g_player_b.x, g_player_b.y, PLAYER_DEAD); dead_b = true; } else { DrawItem(g_player_a.x, g_player_a.y, PLAYER_A); DrawItem(g_player_b.x, g_player_b.y, PLAYER_B); return true; } // 判断是否要重新开始 bool restart = false; if (dead_ab || (dead_a && dead_b)) restart = MessageBox(GetHWnd(), _T("Player A 和 Player B 都死了。\n要再来一局吗?"), _T("GAME OVER"), MB_YESNO | MB_ICONINFORMATION) == IDYES; else if (dead_a) restart = MessageBox(GetHWnd(), _T("Player A 死了。\n要再来一局吗?"), _T("GAME OVER"), MB_YESNO | MB_ICONINFORMATION) == IDYES; else if(dead_b) restart = MessageBox(GetHWnd(), _T("Player B 死了。\n要再来一局吗?"), _T("GAME OVER"), MB_YESNO | MB_ICONINFORMATION) == IDYES; if (restart) { init(); return true; } else return false; } // 主函数 void main() { initgraph(640, 480); srand((unsigned)time(NULL)); // 初始化 init(); // 游戏主循环 while(true) { int cmd = GetCmd(); // 获取用户命令 if (!DealCmd(cmd)) break; // 处理命令 if (!DealGame()) break; // 处理游戏 Sleep(200); // 延时 } // 关闭绘图窗口 closegraph(); }

走迷宫程序(含自动迷宫生成)

这是一个传统的迷宫程序。 屏幕中只能看到迷宫的一小部分,右下角有游戏者在完整地图内的卫星定位点。 游戏执行效果如下: 程序间有足够多的注释,就不多作介绍了。代码如下: /////////////////////////////////////////////////// // 程序名称:迷宫 游戏 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2013霜降版 // 作  者:krissi <zhaoh1987@qq.com> // 最后修改:2011-3-12 // #include <graphics.h> #include <time.h> ////////////////////////////////////////////////////// // 定义全局变量 // BYTE** g_aryMap = NULL; // 迷宫地图 SIZE g_szMap; // 迷宫地图的尺寸 IMAGE g_imgSight(360, 280); // 游戏的视野 RECT g_rtSight; // 游戏的视野的范围 IMAGE g_imgItem(180, 20); // 地图元素 IMAGE g_imgGPS; // 迷你地图,用于显示游戏者在地图中的位置 POINT g_ptGPS; // 迷你地图的显示位置 SIZE g_szGPS; // 迷你地图的尺寸 POINT g_ptPlayer; // 游戏者的位置 // 枚举地图元素,兼做元素位置的 x 坐标 enum MAPITEM { MAP_WALL = 0, MAP_PLAYER = 20, MAP_GROUND = 40, MAP_MARKRED = 60, MAP_MARKGREEN = 80, MAP_MARKYELLOW = 100, MAP_ENTRANCE = 120, MAP_EXIT = 140, MAP_OUTSIDE = 160 }; // 枚举用户的控制命令 enum CMD { CMD_QUIT = 1, CMD_UP = 2, CMD_DOWN = 4, CMD_LEFT = 8, CMD_RIGHT = 16, CMD_MARKRED = 32, CMD_MARKGREEN = 64, CMD_MARKYELLOW = 128, CMD_CLEARMARK = 256 }; ////////////////////////////////////////////////////// // 函数声明 // void Welcome(); // 绘制游戏界面 void InitImage(); // 初始化游戏图片 void InitGame(); // 初始化游戏数据 void GetMazeSize(); // 提示用户输入迷宫大小 void MakeMaze(int width, int height); // 生成迷宫:初始化(注:宽高必须是奇数) void TravelMaze(int x, int y); // 生成迷宫:遍历 (x, y) 四周 MAPITEM GetMazeItem(int x, int y); // 获取指定坐标的迷宫元素 void Paint(); // 绘制视野范围内的迷宫 int GetCmd(); // 获取用户输入的命令 void DispatchCmd(int cmd); // 处理用户输入的命令 void OnUp(); // 向上移动 void OnLeft(); // 向左移动 void OnRight(); // 向右移动 void OnDown(); // 向下移动 void OnMark(MAPITEM value); // 在地图中做标记 bool CheckWin(); // 检查是否到出口 bool Quit(); // 询问用户是否退出游戏 ////////////////////////////////////////////////////// // 函数定义 // // 主程序 void main() { // 初始化 initgraph(640, 480); // 创建绘图窗口 srand((unsigned)time(NULL)); // 设置随机种子 // 显示主界面 Welcome(); // 初始化 InitImage(); InitGame(); // 游戏过程 int c; while( !(((c = GetCmd()) & CMD_QUIT) && Quit()) ) { DispatchCmd(c); Paint(); if (CheckWin()) break; // 延时 Sleep(100); } // 清理迷宫地图占用的内存 for(int x = 0; x < g_szMap.cx + 2; x++) delete[] g_aryMap[x]; delete [] g_aryMap; // 关闭图形模式 closegraph(); } // 绘制游戏界面 void Welcome() { // 绘制渐变色外框 for(int i=0; i<128; i++) { setlinecolor(RGB(0, 0, (127 - i) << 1)); rectangle(149 - i, 109 - (i >> 1), 490 + i, 370 + (i >> 1)); } // 设置字体样式 settextcolor(WHITE); setbkmode(TRANSPARENT); // 绘制标题 settextstyle(36, 0, _T("宋体")); outtextxy(248, 40, _T("迷  宫")); // 绘制操作说明 settextstyle(12, 0, _T("宋体")); outtextxy(50, 382, _T("控制说明:")); outtextxy(74, 400, _T("方向键或 A/S/D/W:移动")); outtextxy(74, 418, _T("空格、Y、G:在地图上做红、黄、绿色 M 标记")); outtextxy(74, 436, _T("C:清除地图上的标记")); outtextxy(74, 454, _T("ESC:退出程序")); } // 初始化游戏图片 void InitImage() { // 预绘制游戏图片到 IMAGE 缓存(可以修改为加载图片以获得更好效果) SetWorkingImage(&g_imgItem); cleardevice(); // 绘制 PLAYER setorigin(MAP_PLAYER, 0); setfillcolor(YELLOW); setlinecolor(YELLOW); fillellipse(2, 2, 17, 17); setlinecolor(BLACK); line(7, 7, 7, 8); line(12, 7, 12, 8); arc(5, 6, 14, 14, 3.34, 6.08); // 绘制墙壁 setorigin(MAP_WALL, 0); settextcolor(BROWN); setfillstyle((BYTE*)"\x20\x20\x20\xff\x04\x04\x04\xff"); setlinecolor(BROWN); solidrectangle(1, 1, 18, 18); rectangle(0, 0, 19, 19); // 绘制红色标记 setorigin(MAP_MARKRED, 0); setlinecolor(RED); moveto(5, 15); linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10); // 绘制绿色标记 setorigin(MAP_MARKGREEN, 0); setlinecolor(GREEN); moveto(5, 15); linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10); // 绘制黄色标记 setorigin(MAP_MARKYELLOW, 0); setlinecolor(YELLOW); moveto(5, 15); linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10); // 绘制入口 setorigin(MAP_ENTRANCE, 0); setlinecolor(GREEN); settextstyle(12, 0, _T("宋体")); outtextxy(4, 4, _T("入")); // 绘制出口 setorigin(MAP_EXIT, 0); outtextxy(4, 4, _T("出")); // 绘制迷宫外面的空地 setorigin(MAP_OUTSIDE, 0); settextcolor(GREEN); setfillstyle((BYTE*)"\x50\x55\x22\x20\x05\x55\x22\x02"); solidrectangle(0, 0, 19, 19); // 恢复坐标系 setorigin(0, 0); // 显示作者 SetWorkingImage(); settextcolor(BLUE); TCHAR author[] = _T("Powered by zhaoh1987@qq.com"); outtextxy(471, 4, author); settextcolor(LIGHTBLUE); outtextxy(470, 3, author); } // 初始化游戏数据 void InitGame() { // 提示用户输入迷宫大小 GetMazeSize(); // 初始化参数 if (g_aryMap != NULL) { // 清理迷宫地图占用的内存 for(int x = 0; x < g_szMap.cx + 2; x++) delete[] g_aryMap[x]; delete [] g_aryMap; } MakeMaze(g_szMap.cx, g_szMap.cy); // 创建迷宫 g_ptPlayer.x = 2; // 设置游戏者的位置 g_ptPlayer.y = 2; g_rtSight.left = 0; // 设置视野范围 g_rtSight.top = 0; g_rtSight.right = 17; g_rtSight.bottom= 13; // 设置 GPS 显示区 setfillcolor(BLUE); solidrectangle(522, 368, 637, 471); if (g_szMap.cx > g_szMap.cy) { g_szGPS.cx = 100; g_szGPS.cy = (int)(100.0 * g_szMap.cy / g_szMap.cx + 0.5); } else { g_szGPS.cy = 100; g_szGPS.cx = (int)(100.0 * g_szMap.cx / g_szMap.cy + 0.5); } Resize(&g_imgGPS, g_szGPS.cx, g_szGPS.cy); g_ptGPS.x = 530 + 50 - g_szGPS.cx / 2; g_ptGPS.y = 370 + 50 - g_szGPS.cy / 2; // 画迷你地图外框 setlinecolor(RED); rectangle(g_ptGPS.x - 1, g_ptGPS.y - 1, g_ptGPS.x + g_szGPS.cx, g_ptGPS.y + g_szGPS.cy); // 画迷你地图入口和出口 setlinecolor(YELLOW); moveto(g_ptGPS.x - 8, g_ptGPS.y + g_szGPS.cy / g_szMap.cy); linerel(7, 0); linerel(-3, -3); moverel(3, 3); linerel(-3, 3); moveto(g_ptGPS.x + g_szGPS.cx, g_ptGPS.y + g_szGPS.cy - g_szGPS.cy / g_szMap.cy); linerel(7, 0); linerel(-3, -3); moverel(3, 3); linerel(-3, 3); // 绘制游戏区 Paint(); } // 提示用户输入迷宫大小 void GetMazeSize() { g_szMap.cx = g_szMap.cy = 0; // 获取用户输入的宽高 TCHAR s[4]; while(g_szMap.cx < 20 || g_szMap.cx > 200) { InputBox(s, 4, _T("请输入迷宫的宽度\n范围:20~200"), _T("输入"), _T("25")); g_szMap.cx = _ttoi(s); } while(g_szMap.cy < 20 || g_szMap.cx > 200) { InputBox(s, 4, _T("请输入迷宫的高度\n范围:20~200"), _T("输入"), _T("25")); g_szMap.cy = _ttoi(s); } // 确保宽高为奇数 if (g_szMap.cx % 2 != 1) g_szMap.cx++; if (g_szMap.cy % 2 != 1) g_szMap.cy++; } // 生成迷宫:初始化(注:宽高必须是奇数) void MakeMaze(int width, int height) { if (width % 2 != 1 || height % 2 != 1) return; int x, y; // 定义迷宫尺寸,并分配迷宫内存 g_aryMap = new BYTE*[width + 2]; for(x = 0; x < width + 2; x++) { g_aryMap[x] = new BYTE[height + 2]; memset(g_aryMap[x], MAP_WALL, height + 2); } // 定义边界 for (x = 0; x <= width + 1; x++) g_aryMap[x][0] = g_aryMap[x][height + 1] = MAP_GROUND; for (y = 1; y <= height; y++) g_aryMap[0][y] = g_aryMap[width + 1][y] = MAP_GROUND; // 定义入口和出口 g_aryMap[1][2] = MAP_ENTRANCE; g_aryMap[width][height - 1] = MAP_EXIT; // 从任意点开始遍历生成迷宫 TravelMaze(((rand() % (width - 1)) & 0xfffe) + 2, ((rand() % (height - 1)) & 0xfffe) + 2); // 将边界标记为迷宫外 for (x = 0; x <= width + 1; x++) g_aryMap[x][0] = g_aryMap[x][height + 1] = MAP_OUTSIDE; for (y = 1; y <= height; y++) g_aryMap[0][y] = g_aryMap[width + 1][y] = MAP_OUTSIDE; } // 生成迷宫:遍历 (x, y) 四周 void TravelMaze(int x, int y) { // 定义遍历方向 int d[4][2] = {0, 1, 1, 0, 0, -1, -1, 0}; // 将遍历方向乱序 int n, t, i; for(i = 0; i < 4; i++) { n = rand() % 4; t = d[i][0], d[i][0] = d[n][0], d[n][0] = t; t = d[i][1], d[i][1] = d[n][1], d[n][1] = t; } // 尝试周围四个方向 g_aryMap[x][y] = MAP_GROUND; for(i = 0; i < 4; i++) if (g_aryMap[x + 2 * d[i][0]][y + 2 * d[i][1]] == MAP_WALL) { g_aryMap[x + d[i][0]][y + d[i][1]] = MAP_GROUND; TravelMaze(x + d[i][0] * 2, y + d[i][1] * 2); // 递归 } } // 获取指定坐标的迷宫元素 MAPITEM GetMazeItem(int x, int y) { return (MAPITEM)g_aryMap[x][y]; } // 绘制视野范围内的迷宫 void Paint() { int x1, y1; // 绘制视野内的迷宫 SetWorkingImage(&g_imgSight); for(int x = g_rtSight.left; x <= g_rtSight.right; x++) for(int y = g_rtSight.top; y <= g_rtSight.bottom; y++) { x1 = (x - g_rtSight.left) * 20; y1 = (y - g_rtSight.top) * 20; putimage(x1, y1, 20, 20, &g_imgItem, GetMazeItem(x, y), 0); } // 绘制游戏者 x1 = (g_ptPlayer.x - g_rtSight.left) * 20; y1 = (g_ptPlayer.y - g_rtSight.top) * 20; putimage(x1, y1, 20, 20, &g_imgItem, MAP_PLAYER, 0); // 绘制迷你地图 SetWorkingImage(&g_imgGPS); cleardevice(); int tx = (int)((g_ptPlayer.x - 1) * g_szGPS.cx / (double)(g_szMap.cx - 1) + 0.5); int ty = (int)((g_ptPlayer.y - 1) * g_szGPS.cy / (double)(g_szMap.cy - 1) + 0.5); setlinecolor(YELLOW); circle(tx, ty, 1); // 更新到绘图窗口 SetWorkingImage(); putimage(150, 110, 340, 260, &g_imgSight, 10, 10); putimage(g_ptGPS.x, g_ptGPS.y, &g_imgGPS); } // 获取用户输入的命令 int GetCmd() { int c = 0; if (GetAsyncKeyState(VK_LEFT) & 0x8000) c |= CMD_LEFT; if (GetAsyncKeyState(VK_RIGHT) & 0x8000) c |= CMD_RIGHT; if (GetAsyncKeyState(VK_UP) & 0x8000) c |= CMD_UP; if (GetAsyncKeyState(VK_DOWN) & 0x8000) c |= CMD_DOWN; if (GetAsyncKeyState('A') & 0x8000) c |= CMD_LEFT; if (GetAsyncKeyState('D') & 0x8000) c |= CMD_RIGHT; if (GetAsyncKeyState('W') & 0x8000) c |= CMD_UP; if (GetAsyncKeyState('S') & 0x8000) c |= CMD_DOWN; if (GetAsyncKeyState(' ') & 0x8000) c |= CMD_MARKRED; if (GetAsyncKeyState('G') & 0x8000) c |= CMD_MARKGREEN; if (GetAsyncKeyState('Y') & 0x8000) c |= CMD_MARKYELLOW; if (GetAsyncKeyState('C') & 0x8000) c |= CMD_CLEARMARK; if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) c |= CMD_QUIT; return c; } // 处理用户输入的命令 void DispatchCmd(int cmd) { if (cmd & CMD_UP) OnUp(); if (cmd & CMD_DOWN) OnDown(); if (cmd & CMD_LEFT) OnLeft(); if (cmd & CMD_RIGHT) OnRight(); if (cmd & CMD_MARKRED) OnMark(MAP_MARKRED); if (cmd & CMD_MARKGREEN) OnMark(MAP_MARKGREEN); if (cmd & CMD_MARKYELLOW) OnMark(MAP_MARKYELLOW); if (cmd & CMD_CLEARMARK) OnMark(MAP_GROUND); } // 向上移动 void OnUp() { if (g_ptPlayer.y > 1 && GetMazeItem(g_ptPlayer.x, g_ptPlayer.y - 1) != MAP_WALL) { g_ptPlayer.y--; if (g_ptPlayer.y - g_rtSight.top < 4 && g_rtSight.top > 0) { g_rtSight.top--; g_rtSight.bottom--; } } } // 向左移动 void OnLeft() { if (g_ptPlayer.x > 1 && GetMazeItem(g_ptPlayer.x - 1, g_ptPlayer.y) != MAP_WALL && GetMazeItem(g_ptPlayer.x - 1, g_ptPlayer.y) != MAP_ENTRANCE) { g_ptPlayer.x--; if (g_ptPlayer.x - g_rtSight.left < 5 && g_rtSight.left > 0) { g_rtSight.left--; g_rtSight.right--; } } } // 向右移动 void OnRight() { if (g_ptPlayer.x < g_szMap.cx && GetMazeItem(g_ptPlayer.x + 1, g_ptPlayer.y) != MAP_WALL) { g_ptPlayer.x++; if (g_rtSight.right - g_ptPlayer.x < 5 && g_rtSight.right <= g_szMap.cx) { g_rtSight.left++; g_rtSight.right++; } } } // 向下移动 void OnDown() { if (g_ptPlayer.y < g_szMap.cy && GetMazeItem(g_ptPlayer.x, g_ptPlayer.y + 1) != MAP_WALL) { g_ptPlayer.y++; if (g_rtSight.bottom - g_ptPlayer.y < 4 && g_rtSight.bottom <= g_szMap.cy) { g_rtSight.top++; g_rtSight.bottom++; } } } // 在地图中做标记 void OnMark(MAPITEM value) { g_aryMap[g_ptPlayer.x][g_ptPlayer.y] = value; } // 检查是否到出口 bool CheckWin() { if (g_ptPlayer.x == g_szMap.cx && g_ptPlayer.y == g_szMap.cy - 1) { HWND hwnd = GetHWnd(); if (MessageBox(hwnd, _T("恭喜你走出来了!\n您想再来一局吗?"), _T("恭喜"), MB_YESNO | MB_ICONQUESTION) == IDYES) { InitGame(); return false; } else return true; } return false; } // 询问用户是否退出游戏 bool Quit() { HWND hwnd = GetHWnd(); return (MessageBox(hwnd, _T("您确定要退出游戏吗?"), _T("询问"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK); }