用C语言写的一个迷宫小游戏,游戏玩法是通过鼠标控制帽子上的灯走出迷宫

// 定义常量

#define PI           3.141592653589      // 圆周率
#define UNIT_GROUND 0                   // 表示地面
#define UNIT_WALL   1                   // 表示墙
#define LIGHT_A     PI / 3              // 灯光的角度范围
#define LIGHT_R     120                 // 灯光的照射距离
#define WIDTH       480                 // 矿井的宽度
#define HEIGHT      480                 // 矿井的高度
#define SCREENWIDTH 640                 // 屏幕宽度
#define SCREENHEIGHT 480                // 屏幕高度
#define UNIT        20                  // 每个墙壁单位的大小
#define PLAYER_R    5                   // 游戏者的半径

// 定义常量

const    SIZE    g_utMap = { 23, 23 };      // 矿井地图的尺寸(基于 UNIT 单位)
const   POINT   g_utPlayer = { 1, 1 }; // 游戏者的位置(基于 UNIT 单位)
const   POINT   g_utExit = { 21, 22 }; // 出口位置(基于 UNIT 单位)
const   POINT   g_ptOffset = { 10, 10 };   // 矿井显示在屏幕上的偏移量

// 定义全局变量

POINT    g_ptPlayer;                     // 游戏者的位置
POINT   g_ptMouse;                      // 鼠标位置
IMAGE   g_imgMap(WIDTH, HEIGHT);        // 矿井平面图
DWORD* g_bufMap;                        // 矿井平面图的显存指针
IMAGE   g_imgRender(WIDTH, HEIGHT);     // 渲染
DWORD* g_bufRender;                 // 渲染的显存指针
DWORD* g_bufScreen;                 // 屏幕的显存指针

// 函数声明

// 初始化
void    Welcome();                                  // 绘制游戏界面
void    ReadyGo();                                  // 准备开始游戏
void    InitGame();                                 // 初始化游戏数据// 矿井生成
void    MakeMaze(int width, int height);            // 初始化(注:宽高必须是奇数)
void    TravelMaze(int x, int y, BYTE** aryMap);    // 遍历 (x, y) 四周
void    DrawWall(int x, int y, bool left, bool top, bool right, bool bottom);
// 画一面墙
// 绘制
void    Paint();                                    // 绘制视野范围内的矿井
void    Lighting(int _x, int _y, double _a);        // 在指定位置和角度“照明”
void    DrawPlayer();                               // 绘制游戏者
void    DrawExit();                                 // 绘制出口// 处理用户控制
int     GetCmd();                                   // 获取用户输入的命令
void    OnUp();                                     // 向上移动
void    OnLeft();                                   // 向左移动
void    OnRight();                                  // 向右移动
void    OnDown();                                   // 向下移动
bool    CheckWin();                                 // 检查是否到出口

// 主函数

// 主程序
void main()
{// 初始化initgraph(SCREENWIDTH, SCREENHEIGHT);        // 创建绘图窗口srand((unsigned)time(NULL));               // 设置随机种子// 显示主界面Welcome();// 游戏过程int c;do{ReadyGo();while (true){// 获得用户输入c = GetCmd();// 处理用户输入if (c & CMD_UP)           OnUp();if (c & CMD_DOWN)        OnDown();if (c & CMD_LEFT)      OnLeft();if (c & CMD_RIGHT)     OnRight();if (c & CMD_RESTART){if (MessageBox(GetHWnd(), _T("您要重来一局吗?"), _T("询问"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK)break;}if (c & CMD_QUIT){if (MessageBox(GetHWnd(), _T("您确定要退出游戏吗?"), _T("询问"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK)break;}// 绘制场景Paint();// 判断是否走出矿井if (CheckWin()){// 是否再来一局HWND hwnd = GetHWnd();if (MessageBox(hwnd, _T("恭喜你走出来了!\n您想再来一局吗?"), _T("恭喜"), MB_YESNO | MB_ICONQUESTION) != IDYES)c = CMD_QUIT;break;}// 延时Sleep(16);}} while (!(c & CMD_QUIT));// 关闭图形模式closegraph();
}

// 其他函数定义

// 准备开始游戏
void ReadyGo()
{// 初始化InitGame();// 停电前兆int time[7] = { 1000, 50, 500, 50, 50, 50, 50 };int i, x, y;for (i = 0; i < 7; i++){if (i % 2 == 0){putimage(0, 0, &g_imgMap);DrawPlayer();DrawExit();}elseclearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);Sleep(time[i]);}// 电力缓慢中断for (i = 255; i >= 0; i -= 5){for (y = (HEIGHT - 1) * SCREENWIDTH; y >= 0; y -= SCREENWIDTH)for (x = 0; x < WIDTH; x++)if (g_bufScreen[y + x] != 0)g_bufScreen[y + x] = g_bufScreen[y + x] - 0x050505;FlushBatchDraw();DrawPlayer();DrawExit();Sleep(50);}// 绘制游戏区Paint();
}// 绘制游戏界面
void Welcome()
{setfillcolor(DARKGRAY);solidrectangle(WIDTH, 0, SCREENWIDTH - 1, SCREENHEIGHT - 1);// 设置字体样式settextcolor(WHITE);setbkmode(TRANSPARENT);// 绘制标题settextstyle(24, 0, _T("宋体"));outtextxy(512, 40, _T("矿井逃生"));// 绘制操作说明RECT r = { 488, 100, 632, 470 };settextstyle(12, 0, _T("宋体"));drawtext(_T("[游戏说明]\n  矿井里的电路又出问题了。迅速借助你的头灯,在漆黑的矿井里\找到出口逃出去吧。\n\n[控制说明]\n方向键: 移动\nA/S/D/W:移动\n鼠标:  控制照射\方向\nF2:   重来一局\nESC:  退出游戏"), &r, DT_WORDBREAK);outtextxy(495, 465, _T("Powered by kx@qq.com"));
}// 初始化游戏数据
void InitGame()
{// 获得窗口显存指针g_bufRender = GetImageBuffer(&g_imgRender);g_bufMap = GetImageBuffer(&g_imgMap);g_bufScreen = GetImageBuffer(NULL);// 设置 Render 环境SetWorkingImage(&g_imgRender);setbkmode(TRANSPARENT);SetWorkingImage(NULL);// 创建矿井MakeMaze(g_utMap.cx, g_utMap.cy);// 设置游戏者位置g_ptPlayer.x = g_utPlayer.x * UNIT + UNIT / 2 + g_ptOffset.x;g_ptPlayer.y = g_utPlayer.y * UNIT + UNIT / 2 + g_ptOffset.y;
}// 生成矿井:初始化(注:宽高必须是奇数)
void MakeMaze(int width, int height)
{if (width % 2 != 1 || height % 2 != 1)return;int x, y;// 定义矿井二维数组,并初始化全部为墙壁// 宽高比实际多 2,是因为两端各有一个“哨兵”,用于方便处理数据BYTE** aryMap = new BYTE * [width + 2];for (x = 0; x < width + 2; x++){aryMap[x] = new BYTE[height + 2];memset(aryMap[x], UNIT_WALL, height + 2);}// 定义边界(哨兵功能)for (x = 0; x <= width + 1; x++)aryMap[x][0] = aryMap[x][height + 1] = UNIT_GROUND;for (y = 1; y <= height; y++)aryMap[0][y] = aryMap[width + 1][y] = UNIT_GROUND;// 从任意点开始遍历生成矿井TravelMaze(((rand() % (width - 1)) & 0xfffe) + 2, ((rand() % (height - 1)) & 0xfffe) + 2, aryMap);// 设置出口aryMap[g_utExit.x + 1][g_utExit.y + 1] = UNIT_GROUND;// 将矿井绘制在 IMAGE 对象上SetWorkingImage(&g_imgMap);cleardevice();for (y = 1; y <= height; y++)for (x = 1; x <= width; x++)if (aryMap[x][y] == UNIT_WALL)DrawWall(x, y, aryMap[x - 1][y] == UNIT_WALL,aryMap[x][y - 1] == UNIT_WALL,aryMap[x + 1][y] == UNIT_WALL,aryMap[x][y + 1] == UNIT_WALL);SetWorkingImage(NULL);
}// 生成矿井:遍历 (x, y) 四周
void TravelMaze(int x, int y, BYTE** aryMap)
{// 定义遍历方向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;}// 尝试周围四个方向aryMap[x][y] = UNIT_GROUND;for (i = 0; i < 4; i++)if (aryMap[x + 2 * d[i][0]][y + 2 * d[i][1]] == UNIT_WALL){aryMap[x + d[i][0]][y + d[i][1]] = UNIT_GROUND;TravelMaze(x + d[i][0] * 2, y + d[i][1] * 2, aryMap);       // 递归}
}// 生成矿井:画一面墙
// 参数:left/top/right/bottom 表示墙壁是否与旁边连接
void DrawWall(int x, int y, bool left, bool top, bool right, bool bottom)
{// 墙壁厚 4 pixelint cx, cy;cx = x * UNIT - UNIT / 2 - 2 + 10;cy = y * UNIT - UNIT / 2 - 2 + 10;if (left) solidrectangle(x * UNIT - UNIT + 10, cy, cx + 4, cy + 4);if (top)    solidrectangle(cx, y * UNIT - UNIT + 10, cx + 4, cy + 4);if (right)  solidrectangle(cx, cy, x * UNIT + 9, cy + 4);if (bottom)  solidrectangle(cx, cy, cx + 4, y * UNIT + 9);
}// 绘制视野范围内的矿井
void Paint()
{// 设置绘图目标为 Render 对象SetWorkingImage(&g_imgRender);// 清空 Render 对象cleardevice();// 计算视野角度double dx, dy, a;dx = g_ptMouse.x - g_ptPlayer.x;dy = g_ptMouse.y - g_ptPlayer.y;if (dx == 0 && dy == 0)a = 0;else if (dx != 0 && dy != 0)a = atan(dy / dx);else if (dx == 0)a = (dy > 0) ? PI / 2 : PI * 3 / 2;elsea = 0;if (dx < 0)  a += PI;if (a < 0) a += PI * 2;// 绘制灯光Lighting(g_ptPlayer.x, g_ptPlayer.y, a);// 画游戏者DrawPlayer();// 画出口DrawExit();// 设置绘图目标为窗口SetWorkingImage(NULL);// 显示到窗口上putimage(0, 0, &g_imgRender);
}// 在指定位置和角度“照明”
void Lighting(int _x, int _y, double _a)
{int i;     // 定义循环变量int x, y;  // 定义临时坐标double a;  // 定义临时角度// 计算灯光照亮的角度区域double a1 = _a - LIGHT_A / 2;double a2 = _a + LIGHT_A / 2;for (a = a1; a < a2; a += PI / 360)                   // 扇形循环{for (int r = 0; r < LIGHT_R; r++)             // 半径循环{// 计算照射到的位置x = (int)(_x + cos(a) * r);y = (int)(_y + sin(a) * r);// 光线超出屏幕范围,终止// (为了简化全凭模糊运算,不处理最上和最下一行)if (x < 0 || x >= WIDTH || y <= 0 || y >= HEIGHT - 1)break;// 光线碰到建筑物,终止if (g_bufMap[y * WIDTH + x])break;// 光线叠加g_bufRender[y * WIDTH + x] += 0x202000;       // 0x202000 是很淡的黄色}}// 计算光照扇形区域的最小包围矩形// 方法:获得 7 个点的最值:圆心、圆弧两端、圆与 xy 轴的 4 个交点// 第一步:初始化 7 个点POINT pt[7];pt[0].x = _x;                                 pt[0].y = _y;pt[1].x = int(_x + LIGHT_R * cos(a1) + 0.5);   pt[1].y = int(_y + LIGHT_R * sin(a1) + 0.5);pt[2].x = int(_x + LIGHT_R * cos(a2) + 0.5);  pt[2].y = int(_y + LIGHT_R * sin(a2) + 0.5);for (a = ceil(a1 * 4 / (2 * PI)) * (PI / 2), i = 3; a < a2; a += PI / 2, i++){pt[i].x = int(_x + LIGHT_R * cos(a) + 0.5);pt[i].y = int(_y + LIGHT_R * sin(a) + 0.5);}// 第二步:获取 7 个点的最大最小值,得到最小包围矩形i--;RECT r = { pt[i].x, pt[i].y, pt[i].x, pt[i].y };for (--i; i >= 0; i--){if (pt[i].x < r.left)  r.left = pt[i].x;if (pt[i].x > r.right) r.right = pt[i].x;if (pt[i].y < r.top)  r.top = pt[i].y;if (pt[i].y > r.bottom) r.bottom = pt[i].y;}// 调整矩形范围if (r.left < 0)                r.left = 0;if (r.top < 1)               r.top = 1;if (r.right >= WIDTH)        r.right = WIDTH - 1;if (r.bottom >= HEIGHT - 1)    r.bottom = HEIGHT - 2;// 修正曝光过度的点for (y = r.top; y <= r.bottom; y++)for (x = r.left; x <= r.right; x++){i = y * WIDTH + x;if (g_bufRender[i] > 0xffff00)g_bufRender[i] = 0xffff00;}// 将光线模糊处理(避开建筑物)for (y = r.top; y <= r.bottom; y++)for (x = r.left; x <= r.right; x++){i = y * WIDTH + x;if (!g_bufMap[i])g_bufRender[i] = RGB((GetRValue(g_bufRender[i - WIDTH]) + GetRValue(g_bufRender[i - 1]) + GetRValue(g_bufRender[i])+ GetRValue(g_bufRender[i + 1]) + GetRValue(g_bufRender[i + WIDTH])) / 5,(GetGValue(g_bufRender[i - WIDTH]) + GetGValue(g_bufRender[i - 1]) + GetGValue(g_bufRender[i])+ GetGValue(g_bufRender[i + 1]) + GetGValue(g_bufRender[i + WIDTH])) / 5,(GetBValue(g_bufRender[i - WIDTH]) + GetBValue(g_bufRender[i - 1]) + GetBValue(g_bufRender[i])+ GetBValue(g_bufRender[i + 1]) + GetBValue(g_bufRender[i + WIDTH])) / 5);}
}// 绘制游戏者
void DrawPlayer()
{// 画安全帽setlinecolor(DARKGRAY);circle(g_ptPlayer.x, g_ptPlayer.y, 5);
}// 绘制出口
void DrawExit()
{settextstyle(12, 0, _T("宋体"));outtextxy(g_utExit.x * UNIT + g_ptOffset.x, g_utExit.y * UNIT + g_ptOffset.y + 8, _T("出口"));
}// 获取用户输入的命令
int GetCmd()
{int c = 0;if ((GetAsyncKeyState(VK_LEFT) & 0x8000) ||(GetAsyncKeyState('A') & 0x8000))      c |= CMD_LEFT;if ((GetAsyncKeyState(VK_RIGHT) & 0x8000) ||(GetAsyncKeyState('D') & 0x8000))      c |= CMD_RIGHT;if ((GetAsyncKeyState(VK_UP) & 0x8000) ||(GetAsyncKeyState('W') & 0x8000))        c |= CMD_UP;if ((GetAsyncKeyState(VK_DOWN) & 0x8000) ||(GetAsyncKeyState('S') & 0x8000))     c |= CMD_DOWN;if (GetAsyncKeyState(VK_F2) & 0x8000)        c |= CMD_RESTART;if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)     c |= CMD_QUIT;MOUSEMSG m;while (MouseHit()){m = GetMouseMsg();g_ptMouse.x = m.x;g_ptMouse.y = m.y;}return c;
}// 向上移动
void OnUp()
{int i = (g_ptPlayer.y - 6) * WIDTH + (g_ptPlayer.x - 5) + 1;int j;for (j = 0; j < 5; j++, i += 2)if (g_bufMap[i])break;if (j == 5)g_ptPlayer.y--;
}// 向左移动
void OnLeft()
{int i = (g_ptPlayer.y - 5) * WIDTH + (g_ptPlayer.x - 5);int j;for (j = 0; j < 5; j++, i += WIDTH)if (g_bufMap[i])break;if (j == 5)g_ptPlayer.x--;
}// 向右移动
void OnRight()
{int i = (g_ptPlayer.y - 5) * WIDTH + (g_ptPlayer.x + 5) + 1;int j;for (j = 0; j < 5; j++, i += WIDTH)if (g_bufMap[i])break;if (j == 5)g_ptPlayer.x++;
}// 向下移动
void OnDown()
{int i = (g_ptPlayer.y + 5) * WIDTH + (g_ptPlayer.x - 5) + 1;int j;for (j = 0; j < 5; j++, i += 2)if (g_bufMap[i])break;if (j == 5)g_ptPlayer.y++;
}// 检查是否到出口
bool CheckWin()
{return (g_ptPlayer.y >= g_utExit.y * UNIT + UNIT / 2 + g_ptOffset.y);
}

希望对大家写游戏思路有所帮助,需要完整代码的同学加QQ群【806041599】找管理员领取哦!

分享一个C语言矿井逃生迷宫小游戏【附源码】相关推荐

  1. html实现扫雷小游戏(附源码)

    文章目录 实现功能 1.扫雷设计 1.1 主界面 1.2 扫雷难度 1.3 附带功能 2.效果和源码 2.1 动态效果 2.2 源代码 源码下载 作者:xcLeigh 文章地址:https://blo ...

  2. 用C语言easyx库来写一个简单的翻翻乐小游戏(附源码素材)

    简明目录 写在前面 easyx库 准备工作 新建项目文件 分析 素材分析 上代码吧 地图表示 开始界面 地图初始化(打乱) 游戏过程实现 主函数的实现 测试 优化 1.游戏分数 2.游戏时间 3.nu ...

  3. android仿IT之家、炫酷水波纹、Kotlin MVP项目、后台模拟点击、蜂巢迷宫小游戏等源码...

    Android精选源码 Android 炫酷的多重水波纹源码 Android开发一款基于行为识别和个性化推荐的智能推荐APP 仿IT之家Android源码 android判断App位于前台或者后台源码 ...

  4. android仿IT之家、炫酷水波纹、Kotlin MVP项目、后台模拟点击、蜂巢迷宫小游戏等源码

    Android精选源码 Android 炫酷的多重水波纹源码 Android开发一款基于行为识别和个性化推荐的智能推荐APP 仿IT之家Android源码 android判断App位于前台或者后台源码 ...

  5. C语言实现三子棋小游戏(源码+教程)

    我猜中了开头,却猜不到这结局.--<大话西游> 目录 1.设计框架 2.设计流程 2.1菜单 2.2初始化棋子 2.3初始化棋盘 2.4玩家输入落子的坐标 2.5电脑随机生成棋子 2.6判 ...

  6. 【Python游戏】基于pygame实现的一个Dino Rush 恐龙宝贝冲冲冲的小游戏 | 附源码

    前言 halo,包子们晚上好 很久没有更新啦,主要是小编这边最近有点小忙 今天给大家整一个Dino Rush 恐龙宝贝冲冲冲的小游戏 还是一个比较记经典的小游戏,还记这可谷歌浏览器上没有网也能打发时间 ...

  7. 【Python游戏】基于化学方程式的基础上,用Python实现一个消灭泡泡小游戏 | 附源码

    前言 halo,包子们下午好 今天实现的这个小游戏呀,说实话化学不太好的小伙伴可能看起来会有点懵逼 不过不用担心,咱们今天不是来学化学的,我们是来学习Python的 所以呀,不要太担心啦,大家先好好看 ...

  8. 【Python游戏】用Python 和 Pyglet 编写一个我的世界小游戏 | 附源码

    相关文件 想学Python的小伙伴可以关注小编的公众号[Python日志] 有很多的资源可以白嫖的哈,不定时会更新一下Python的小知识的哈!! 需要源码的小伙伴可以在公众号回复我的世界 Pytho ...

  9. 【Python游戏】Python基于pygame实现的人机大战的斗兽棋小游戏 | 附源码

    前言 有粉丝说要我出一期Python版本的斗兽棋,今天宠粉狂魔的我不就来啦!! 虽然是一个简单的小游戏,但是对于新手小伙伴来说还是有一定的小难度的哟!要是不理解都可以找到小编的哈!! 相关文件 关注小 ...

最新文章

  1. Android Intent 大全[转载]
  2. java 多项式拟合最多的项数_牛顿插值法、曲线拟合、多项式拟合
  3. K NEAREST NEIGHBOR 算法(knn)
  4. beego1---beego,bee环境配置
  5. 十五、MySQL变量(系统变量、自定义变量)相关知识总结
  6. 投票选举 算法_区块链主流共识算法一文全通
  7. CVPR 2022 中科院、腾讯提出LAS-AT,利用“可学习攻击策略”进行“对抗训练”
  8. 【实习之T100开发】Linux 学习笔记
  9. nginx源码分析:打开监听套接字的流程
  10. php可逆加密解密函数,php 好用可逆的 加密解密 函数。
  11. C++11中智能指针的原理、使用、实现
  12. 最全的 Charles 抓包工具详解
  13. Idea 中图片资源无法加载问题
  14. Linux安装vim不成功(没有可用的软件包)解决方法
  15. 删除WPS 遗留的qingnse64XXX.dll
  16. Linux那些事儿 之 戏说USB(21)向左走,向右走
  17. 网站访客QQ获取系统
  18. 计算机图像分析系统属于,智能图像分析系统
  19. 数据分散情况的统计图-盒须图
  20. 收藏能力升级,支付宝版「小程序桌面」初现!

热门文章

  1. 天玑9200和骁龙8+哪个好 天玑9200和骁龙8+gen1对比
  2. stata软件不出图_stata 如何导出绘制的图?
  3. switch c语言格式,switch语句格式是什么
  4. P6857 梦中梦与不再有梦
  5. 东方通TongWeb部署
  6. Go语言圣经 - 第3章 基础数据类型
  7. 马尔代夫的华为“新4军”
  8. 换帅之后,IBM能否再度起舞?
  9. 推广网站的26种方法
  10. (附源码)计算机毕业设计SSM装修信息分享管理系统