分享一个C语言矿井逃生迷宫小游戏【附源码】
用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语言矿井逃生迷宫小游戏【附源码】相关推荐
- html实现扫雷小游戏(附源码)
文章目录 实现功能 1.扫雷设计 1.1 主界面 1.2 扫雷难度 1.3 附带功能 2.效果和源码 2.1 动态效果 2.2 源代码 源码下载 作者:xcLeigh 文章地址:https://blo ...
- 用C语言easyx库来写一个简单的翻翻乐小游戏(附源码素材)
简明目录 写在前面 easyx库 准备工作 新建项目文件 分析 素材分析 上代码吧 地图表示 开始界面 地图初始化(打乱) 游戏过程实现 主函数的实现 测试 优化 1.游戏分数 2.游戏时间 3.nu ...
- android仿IT之家、炫酷水波纹、Kotlin MVP项目、后台模拟点击、蜂巢迷宫小游戏等源码...
Android精选源码 Android 炫酷的多重水波纹源码 Android开发一款基于行为识别和个性化推荐的智能推荐APP 仿IT之家Android源码 android判断App位于前台或者后台源码 ...
- android仿IT之家、炫酷水波纹、Kotlin MVP项目、后台模拟点击、蜂巢迷宫小游戏等源码
Android精选源码 Android 炫酷的多重水波纹源码 Android开发一款基于行为识别和个性化推荐的智能推荐APP 仿IT之家Android源码 android判断App位于前台或者后台源码 ...
- C语言实现三子棋小游戏(源码+教程)
我猜中了开头,却猜不到这结局.--<大话西游> 目录 1.设计框架 2.设计流程 2.1菜单 2.2初始化棋子 2.3初始化棋盘 2.4玩家输入落子的坐标 2.5电脑随机生成棋子 2.6判 ...
- 【Python游戏】基于pygame实现的一个Dino Rush 恐龙宝贝冲冲冲的小游戏 | 附源码
前言 halo,包子们晚上好 很久没有更新啦,主要是小编这边最近有点小忙 今天给大家整一个Dino Rush 恐龙宝贝冲冲冲的小游戏 还是一个比较记经典的小游戏,还记这可谷歌浏览器上没有网也能打发时间 ...
- 【Python游戏】基于化学方程式的基础上,用Python实现一个消灭泡泡小游戏 | 附源码
前言 halo,包子们下午好 今天实现的这个小游戏呀,说实话化学不太好的小伙伴可能看起来会有点懵逼 不过不用担心,咱们今天不是来学化学的,我们是来学习Python的 所以呀,不要太担心啦,大家先好好看 ...
- 【Python游戏】用Python 和 Pyglet 编写一个我的世界小游戏 | 附源码
相关文件 想学Python的小伙伴可以关注小编的公众号[Python日志] 有很多的资源可以白嫖的哈,不定时会更新一下Python的小知识的哈!! 需要源码的小伙伴可以在公众号回复我的世界 Pytho ...
- 【Python游戏】Python基于pygame实现的人机大战的斗兽棋小游戏 | 附源码
前言 有粉丝说要我出一期Python版本的斗兽棋,今天宠粉狂魔的我不就来啦!! 虽然是一个简单的小游戏,但是对于新手小伙伴来说还是有一定的小难度的哟!要是不理解都可以找到小编的哈!! 相关文件 关注小 ...
最新文章
- Android Intent 大全[转载]
- java 多项式拟合最多的项数_牛顿插值法、曲线拟合、多项式拟合
- K NEAREST NEIGHBOR 算法(knn)
- beego1---beego,bee环境配置
- 十五、MySQL变量(系统变量、自定义变量)相关知识总结
- 投票选举 算法_区块链主流共识算法一文全通
- CVPR 2022 中科院、腾讯提出LAS-AT,利用“可学习攻击策略”进行“对抗训练”
- 【实习之T100开发】Linux 学习笔记
- nginx源码分析:打开监听套接字的流程
- php可逆加密解密函数,php 好用可逆的 加密解密 函数。
- C++11中智能指针的原理、使用、实现
- 最全的 Charles 抓包工具详解
- Idea 中图片资源无法加载问题
- Linux安装vim不成功(没有可用的软件包)解决方法
- 删除WPS 遗留的qingnse64XXX.dll
- Linux那些事儿 之 戏说USB(21)向左走,向右走
- 网站访客QQ获取系统
- 计算机图像分析系统属于,智能图像分析系统
- 数据分散情况的统计图-盒须图
- 收藏能力升级,支付宝版「小程序桌面」初现!