热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c++编程迷宫小游戏

如何才能提供自己的编程水平,就要千锤百炼。main.cpp#includelabyrith.h

如何才能提供自己的编程水平,就要千锤百炼。

main.cpp


#include "labyrith.h"
// 主函数
int main()
{
FrameWindow frame; // 建立图形界面
frame.Run(); // 运行控制函数
while(1) // 主循环
{
frame.Run(); // 运行控制
}
getch(); // 当有按键的时候关闭图形
closegraph();
return 0;
}

labyrinth.cpp

#include "labyrith.h"
int Wall[22][22]; // 墙壁
int entranceX; // 入口
int entranceY;
int exitX; // 出口
int exitY;
// 默认构造函数
FrameWindow::FrameWindow()
{
initgraph(960, 660); // 建立图形界面
setbkcolor(LIGHTGREEN); // 设置背景颜色为亮绿色
direct = 0; // 设置 direct 的初值为 0
cOntrol= 0; // 默认控制权为 0
loadimage(&img, "res\\bk.jpg", 29, 29); // 加载图片
}
// 运行控制
void FrameWindow::Run()
{
cleardevice(); // 清屏
NewBackground(); // 绘制新背景图
DrawSome(); // 绘制些神马
cOntrol= 0; // 首先将函数对程序程序的控制权置 0
direct = 0; // 设置 direct 的初值为 0
// 主循环
while(1)
{
if(kbhit()) // 检测按键
{
direct = getch(); // 从按键获取输入
mciSendString("play res\\key.wav", NULL, 0, NULL); // 按键声
if( direct == 115 && cOntrol== 0) // s 的键值为 115
{
StartDrawLabyrith(); // 开始绘制迷宫
}
if(direct == 101 && cOntrol== 2) // e 的键值为 101
{
SetLabyrith(); // 设置迷宫的入口和出口
}
if(direct == 100 && cOntrol== 3) // d 的键值为 100
{
cOntrol= -1; // 将 control 设置为 -1 的目的是
// 让程序从 Demo() 回到 Run() 时只响应刷新操作
Demo(); // 寻找路径并演示
}
if(direct == 63 && (cOntrol== 0 || cOntrol== -1)) // 按 F5 刷新
{
break;
}
}
else
{
Sleep(10);
}
}
}
// 绘制新背景
void FrameWindow::NewBackground()
{
float H, S, L; // 定义 HSL 颜色模型的 3 个变量
H = 110; // 色相
S = 1; // 饱和度
L = 0.4522f; // 亮度
for(int y = 0; y != 660; ++y) // 绘制迷宫背景颜色
{
L += 0.000125f;
S -= 0.00125f;
setcolor(HSLtoRGB(H, S, L));
line(0, y, 660, y);
}
H = 50; // 色相
S = -3.2555f; // 饱和度
L = 0.525617f; // 亮度
for(int y = 0; y != 660; ++y) // 绘制提示信息部分背景
{
L += 0.000000085f;
S -= 0.0015f;
setcolor(HSLtoRGB(H, S, L));
line(660, y, 960, y);
}
}
// 绘制些神马
void FrameWindow::DrawSome()
{
setcolor(LIGHTRED);
for(int i = 0; i <22; ++i)
{
// 外围墙壁在 Wall 数组中的位置置 1
Wall[0][i] = 1;
Wall[i][0] = 1;
Wall[21][i] = 1;
Wall[i][21] = 1;
// 绘制外围墙壁
putimage(0 * 30 + 1, i * 30 + 1, &img);
putimage(i * 30 + 1, 0 * 30 + 1, &img);
putimage(631, i * 30 + 1, &img);
putimage(i * 30 + 1, 631, &img);
putimage(931, i * 30 + 1, &img);
line(i * 30, 0, i * 30, 660); // 绘制格子线
line(0, i * 30, 660, i * 30); // 绘制格子线
}
for(int i = 0; i <10; ++i) // 绘制提示区域外围框
{
putimage(i * 30 + 661, 1, &img);
putimage(i * 30 + 661, 631, &img);
}
for(int i = 1; i <= 20; ++i) // 其它的 Wall 数组的值暂时置 0
{
for(int j = 1; j <= 20; ++j)
{
Wall[i][j] = 0;
}
}
// 绘制提示信息
RECT r = {710, 40, 900, 300};
setbkmode(TRANSPARENT); // 设置输出文字背景模式为透明
setcolor(BLUE); // 设置输出文字颜色
setfont(15, 0, "宋体");

// 输出提示信息
drawtext("游戏操作介绍:\n\n按键 S:绘制迷宫。\n鼠标左键绘制墙壁,\
鼠标右键擦除墙壁。\n\n按键 E:设置迷宫的入口和出口。\n使用鼠标\
左键来设置入口和出口,右键取消设置。\n\n按键 D:进行迷宫的探索\
,寻找从入口到出口的最短路径,由小球来演示从入口到出口的路径。",
&r, DT_WORDBREAK);
setbkmode(OPAQUE); // 恢复默认填充颜色
// 输出提示信息
outtextxy(730, 400, "迷宫状态: ");
outtextxy(810, 400, "等待绘制");
outtextxy(750, 500, "按 F5 重新开始");
}
// 开始绘制迷宫
void FrameWindow::StartDrawLabyrith()
{
int x = 0, y = 0; // 标记鼠标的坐标使用
outtextxy(810, 400, "正在绘制"); // 修改迷宫状态
FlushMouseMsgBuffer(); // 清空鼠标消息缓冲区

// 主循环
while(1)
{
if(kbhit())
{
direct = getch(); // 获取按键信息
mciSendString("play res\\key.wav", NULL, 0, NULL); // 按键声
if(direct == 101) // e 的键值为 101
{
cOntrol= 2; // 控制权值为 2
break;
}
else if(direct == 63) // F5 刷新
{
break;
}
}
else if(MouseHit())
{
msg = GetMouseMsg(); // 获取鼠标消息
x = msg.x / 30; // 获取鼠标所在格子在 Wall 中的位置
y = msg.y / 30;
if(msg.x > 30 && msg.x <630 && msg.y > 30 && msg.y <630) // 只能在这个区域里面响应鼠标消息
{
switch(msg.uMsg) // 消息的种类
{
case WM_LBUTTONDOWN: // 左键按下
{
Wall[y][x] = 1; // y 对应行, x 对应列, 将对应的位置置 1
putimage(x * 30 + 1, y * 30 +1, &img); // 放置图片
}
break;
case WM_RBUTTONDOWN: // 右键按下
{
Wall[y][x] = 0; // y 对应行, x 对应列, 将对应的位置置 0
PrintGrid(x * 30, y * 30); // 重新绘制这个格子
setcolor(BLUE );
}
break;
default:break;
}
}
}
else
{
Sleep(10);
}
}
}
// 设置入口和出口
void FrameWindow::SetLabyrith()
{
int x = 0, y = 0; // 临时参数
entranceX = -1; // 入口
entranceY = -1;
exitX = -1; // 出口
exitY = -1;
outtextxy(810, 400, "设置入口"); // 提示信息

// 主循环
while(1)
{
if(kbhit()) // 键盘消息
{
direct = getch(); // 获取消息
mciSendString("play res\\key.wav", NULL, 0, NULL); // 按键声
if(direct == 100 && entranceX != -1 && exitX != -1) // 如果出入口都设置好, 按 d 键退出设置模式
{
cOntrol= 3; // 控制权变为 3, 回到 Run 中由其判断由谁控制程序;
break;
}
else if(direct == 63) // F5 刷新
{
cOntrol= 0;
break;
}
}
else if(MouseHit())
{
msg = GetMouseMsg(); // 获取鼠标消息
x = msg.x / 30; // 获取鼠标所在格子在 Wall 中的位置
y = msg.y / 30;
if(entranceX != -1 && exitX != -1) // 完成设置
{
outtextxy(810, 400, "设置完成");
}
if(msg.x > 30 && msg.x <630 && msg.y > 30 && msg.y <630) // 只能在这个区域里面响应鼠标消息
{
if(Wall[y][x] == 0 && msg.uMsg == WM_LBUTTONDOWN) // 如果这个位置不是墙壁, 并且按下左键
{
if(entranceX == -1 && (exitX != x || exitY != y)) // 确保此处没被设置
{
entranceX = x; // 入口位置
entranceY = y;
Wall[y][x] = 1;
outtextxy(x * 30 + 8, y * 30 + 10,_T("In")); // 将此处标记为 In
if(exitX == -1) // 若此时还未设置出口
{
outtextxy(810, 400, "设置出口"); // 改变迷宫状态
}
}
else if(exitX == -1 && (entranceX != x || entranceY != y)) // 此处未设置出口且不是入口位置
{
exitX = x; // 出口位置
exitY = y;
Wall[y][x] = 1;
outtextxy(x * 30 + 4, y * 30 + 8,_T("Out")); // 将此处标记为 Out
if(entranceX == -1) // 若此时还未设置入口
{
outtextxy(810, 400, "设置入口"); // 改变迷宫状态
}
}
}
else if(Wall[y][x] == 1 && msg.uMsg == WM_RBUTTONDOWN) // 如果这个位置不是墙壁, 并且按下右键
{
if(x == entranceX && y == entranceY) // 取消设置入口
{
entranceX = -1;
entranceY = -1;
Wall[y][x] = 0;
outtextxy(810, 400, "设置入口"); // 改变迷宫状态
PrintGrid(x * 30, y * 30); // 从新绘制格子
setcolor(BLUE); // 恢复原线条颜色
}
else if(x == exitX && y == exitY) // 取消设置出口
{
exitX = -1;
exitY = -1;
Wall[y][x] = 0;
outtextxy(810, 400, "设置出口"); // 改变迷宫状态
PrintGrid(x * 30, y * 30); // 重新绘制格子
setcolor(BLUE); // 恢复原线条颜色
}
}
}
}
}
}
// 探索迷宫路径, 并演示成果
void FrameWindow::Demo()
{
Queue qu;
Node node;
int zx[4] = {1,0,-1,0},zy[4] = {0,1,0,-1}; // 四个方向
int find = 0; // find 值为 1 表示结束寻找路径
int x = 0, y = 0; // 临时参数 x, y
node.x = entranceX; // 入口位置
node.y = entranceY;
outtextxy(810, 400, "正在演示"); // 更改迷宫状态
qu.Push(node); // 入队操作
// 广度搜索算法寻找最短路径
while(qu.GetFront() {
node.x = qu.visit(qu.GetFront()).x; // 新队头的坐标
node.y = qu.visit(qu.GetFront()).y;
for(int i = 0; i <4; ++i) // 朝四个方向探索
{
x = node.x;
y = node.y;
node.x += zx[i];
node.y += zy[i];
if(Wall[node.y][node.x] == 0) // 如果旁边的位置不是墙壁并且没有被访问
{
qu.Push(node); // 将此位置加入队列
Wall[node.y][node.x] = 1;
}
if(node.x == exitX && node.y == exitY) // 找到出口位置
{
qu.Push(node); // 将出口位置加入队列
find = 1; // find 置 1, 表示找到出口
break;
}
node.x = x;
node.y = y;
}
qu.Pop(); // 将队头出队
}
if(find == 1) // 如果找到出口
{
qu.ResetPre(); // 重置节点前驱
qu.PrintRoute(); // 输出路径
}
else
{
outtextxy(760, 440, "不存在路径"); // 否则, 视为不存在路径
}
}
// 绘制新格子
void PrintGrid(int x, int y)
{
float H = 110, S = 1, L = 0.4522f; // 设置 H S L的初值
S -= (float)y * 0.00125f; // 设置 S 在这线条的值
L += (float)y * 0.000125f; // 设置 L 在这个线条上
for(int i = y + 1; i {
L += 0.000125f;
S -= 0.00125f;
setcolor(HSLtoRGB(H, S, L));
line(x + 1, i, x + 29, i);
}
}
// 默认构造函数
Queue::Queue()
{
data = new Node[QueueMaxLength]; // 申请队列存储空间
frOnt= 0; // 队头为 0
rear = 0; // 队尾为 0
}
// 析构函数
Queue::~Queue()
{
delete (data); // 释放队列存储空间
}
// 出队操作
void Queue::Pop()
{
++front; // 出队操作
}
// 入队操作
void Queue::Push(Node node)
{
data[rear].x = node.x;
data[rear].y = node.y;
if(rear == 0) // 如果是第一个元素入队, 将其前驱指向空
{
data[rear].pre = NULL;
}
else
{
data[rear].pre = &data[front]; // 不是, 将前驱指向队头
}
++rear; // 队尾加 1
}
// 获取队头
inline int Queue::GetFront()
{
return front;
}
// 获取队尾
inline int Queue::GetRear()
{
return rear;
}
// 访问队列
Node Queue::visit(int i)
{
return data[i];
}
// 重置节点前驱
void Queue::ResetPre()
{
Node *s = &data[rear - 1]; // 指向出口
Node *p = s->pre; // 出口的前驱
Node *r ;
// 主循环
while(1)
{
r = p->pre; // r 指向 p 的前驱
p->pre = s; // p 的前驱指向 s
s = p; // s 指向 p
p = r; // p 指向 r
if(r == NULL) // 如果 r 为空, 退出循环
{
break;
}
}
}
// 输出路径
void Queue::PrintRoute()
{
Node * s = data[0].pre; // 入口位置
// 主循环
while(s != &data[rear - 1])
{
setfillstyle(LIGHTRED); // 设置填充颜色
// 绘制圆
fillcircle(s->x * 30 + 15, s->y * 30 + 15, 10);
Sleep(100);
s = s->pre; // s 指向其前驱
}
outtextxy(810, 400, "演示完成"); // 改变迷宫状态
}

labyrith.h

#ifndef labyrith_h
#define labyrith_h
#include
#include
#include
#include
#pragma comment(lib, "WINMM.LIB")
using namespace std;
int const QueueMaxLength = 1000; // 堆栈最大长度
struct Node // 定义一个节点
{
int x; // 保存矩形的 x 坐标
int y; // 保存矩形的 y 坐标
Node *pre; // 保存其根节点
};
class FrameWindow // 定义一个窗口框架
{
private:
IMAGE img; // 墙壁图片
int direct; // 接受特殊按键时结束绘制迷宫
int control; // 标记程序控制控制权
MOUSEMSG msg; // 鼠标消息
public:
FrameWindow(); // 默认构造函数
void NewBackground(); // 绘制新背景
void DrawSome(); // 绘制些什么
void Run(); // 运行控制
void StartDrawLabyrith(); // 开始绘制迷宫
void SetLabyrith(); // 设置迷宫
void Demo(); // 寻找路径, 并演示
};
class Queue // 定义队列类
{
private:
Node *data; // 数据域
int front; // 队头
int rear; // 队尾
public:
Queue(); // 队列默认构造函数
~Queue(); // 析构函数
void Pop(); // 出队操作
void Push(Node node); // 入队操作
void ResetPre(); // 重置节点前驱
Node visit(int i); // 访问节点
inline int GetFront(); // 获取队头
inline int GetRear(); // 获取队尾
void PrintRoute(); // 打印路径
};
void PrintGrid(int x, int y); // 在用户取消设置某格子为墙壁之后, 从新绘制格子
extern int Wall[22][22]; // 墙壁标记数组
extern int entranceX; // 入口
extern int entranceY;
extern int exitX; // 出口
extern int exitY;
#endif

运行结果:

 下载链接:

        https://download.csdn.net/download/EDU_YONG/85501843

或者私信我:免费提供。


推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 广度优先遍历(BFS)算法的概述、代码实现和应用
    本文介绍了广度优先遍历(BFS)算法的概述、邻接矩阵和邻接表的代码实现,并讨论了BFS在求解最短路径或最短步数问题上的应用。以LeetCode中的934.最短的桥为例,详细阐述了BFS的具体思路和代码实现。最后,推荐了一些相关的BFS算法题目供大家练习。 ... [详细]
author-avatar
mumei4_839_210
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有