C++基于EasyX制作贪吃蛇游戏(三)第二版文档
本文首发于我的个人博客www.colourso.top,欢迎来访。
填补一下原来留下来的坑,上接 C++基于EasyX制作贪吃蛇游戏(一)文档 继续更新制作贪吃蛇游戏的一些相关设计。
游戏界面设置
游戏界面分为四个区域:
- 游戏区:贪吃蛇游戏、动画展示的区域。
- 玩法介绍区:主要描述游戏控制相关内容。
- 数据展示区:展示游戏的分数、蛇身长度以及速度信息。
- 游戏状态区:显示游戏当前状态,运行、暂停还是游戏结束。
游戏展示画面的思路
整个程序是基于Easyx图形库进行制作的,所以界面的全部内容都是调用相关函数绘制上去的。
提到绘制,最初的想法就是在整个程序运行的大循环之中,每次循环开始之时重新绘制整个界面的内容,这就需要保存蛇的节点以及食物、还有其他三个区域的信息,每次重新进行绘制。
但是这样感觉效率可能会是问题,所以在设计之初,就采用了局部绘制与擦除的方式。
- 局部绘制:就是单独绘制界面需要更新的位置,而不需要重新绘制整个界面。
- 擦除方式:这里采用了使用背景色黑色进行覆盖的方式,整个界面背景色都是黑色,不需要的部分直接使用黑色矩阵进行覆盖掉,那么在外观上看来就是擦除的效果。
例如蛇身体的绘制就是采用的局部绘制:
正常情况下蛇前进一格,就是蛇头向某个方向行走一格,然后蛇头后的其他节点都是依次复制前一个节点的位置,然后最后一个节点空余出来。这时候只需要单独绘制一个蛇的头部节点,然后擦除掉蛇的尾部节点走过的地方即可。
当然当数据展示区以及游戏状态区的内容需要更新的时候也是采用擦除然后局部绘制的方式。
当然这样会有一些不妥,如果你想把背景设置为一张图片,这种做法就会失效,当想在图片上绘制内容或者修改内容时,整个显示界面都需要重新进行绘制。
显示蛇头
第一版程序之中没有区分蛇头与蛇身,无论时观察还是游玩都有些不太明显。
因为蛇是一个链表的数据结构,蛇头就是链表的头节点。只需要额外对头节点绘制特殊的图形,然后擦除掉原先头节点即可。
//在蛇头部节点的数据更新之后
drawsnakehead(*(snake.head));//画新的头部
drawsnakenode(*(snake.head->next));//将原来的头部变成身体的颜色
蛇的速度
所谓的控制蛇的速度,也就是控制蛇每次前进一格的速度,简单点就是控制每个循环中最终Sleep()
的时间。
延迟等待时间越长、蛇的速度也就越慢。
#define MAX_SPEED 5 //最大速度
#define MIN_SPEED 29 //最小速度
#define ORG_SPEED 18 //原始速度
int g_speed = ORG_SPEED; //控制速度,全局变量
这里定义三个宏,对应允许的最大速度、最小速度和原始速度。
然后定义一个全部变量g_speed
来保存速度。
这里的速度对应的Slepp()
延迟是1:10的关系,即Sleep(g_speed*10)
。
按键控制蛇的速度
在设定中c键加速,x键减速,z键恢复原始速度。
就在代码中的按键监听部分加上相应的代码。
bool speedchange = false;
if (_kbhit())
{
char key = _getch();
switch (key)
{
case 99: //c 加速
if (g_speed > MAX_SPEED)
{
g_speed -= 1;
speedchange = true;
}
break;
case 120: //x 减速
if (g_speed < MIN_SPEED)
{
g_speed += 1;
speedchange = true;
}
break;
case 122: //z 回归原速
g_speed = ORG_SPEED;
speedchange = true;
break;
}
}
如果速度改变了,那就将speedchange
置为true,便于之后在数据显示区进行是否刷新的判断。
显示蛇的速度
定义蛇的速度等级不能简单粗暴的从5到29,不直观。直接采用30 - g_speed
这样的方式,得到的结果就是1到25级,初始默认是12级,等级越低速度越慢,玩家可以自行调节速度等级。
游戏暂停与继续
刚开始想这个问题的时候头疼了一下,如何让一个死循环停止运行呢,答案是进入另一个死循环就行了。
设定的是空格键暂停与继续,在按键监听那里加入空格键32
。当按了空格键之后就直接进入了另一个循环,整个界面游戏循环就暂时停滞了。
在另一个循环中一直处于按键监听等待空格键的再次按下,break循环,从而回到原来的大循环中,继续执行,这样就达到了暂停的效果。
case 32: //空格暂停
drawpause(); //状态区显示
while (true)
{
if (_kbhit())
{
char key = _getch();
if (key == 32) //按空格继续
{
clearstate();
drawruntime(); //绘制程序正在运行中
break;
}
}
}
break;
当然要在对应的游戏状态区给出提示,让人知道这个游戏是暂停了,而非卡死了。
游戏重新开始
当失败的时候,可以选择重新开始游戏或者是退出游戏。
如何重新开始一个游戏呢?我的思路是将整个游戏的玩耍过程封装成一个函数,当我们最后游戏结束的时候,调用这个函数就能够重新开始了。
那么以为着要改动一下原来第一版的函数结构了。
- 将原先程序中的
init()
函数中的数据初始化部分拿出来创建成initdata()
函数。 - 原先的函数主体是
drawgame()
绘制游戏初始界面,以及gameplay()
游戏玩耍控制,这两个函数。- 现在将这两个函数以及
initdata()
三个函数封装成一个play()
函数,当需要开始游戏时直接调用play()
函数即可。
- 现在将这两个函数以及
当游戏结束的时候会给出提示r键重新开始、q键退出游戏,这一部分也是按键检测和控制的,参照上面的按键检测代码也是很容易写出来的。
其他
关于数据展示以及游戏状态展示这一部分的代码就不详细介绍了,比较简单。
还有问题就是在中文输入法下按键会优先弹出输入法的框,需要手动将输入法切换为英文。
大致这样吧,后续再更新代码。
原文地址:https://www.cnblogs.com/colourso/p/12989699.html
- 高斯消元模版
- HDU 1728 逃离迷宫(DFS经典题,比赛手残写废题)
- 洛谷 P1219 八皇后【经典DFS,温习搜索】
- KVM基于内核的虚拟机概念理解与客户机浅析
- 洛谷 P1972 [SDOI2009]HH的项链【莫队算法学习】
- BZOJ 2257: [Jsoi2009]瓶子和燃料【数论:裴蜀定理】
- 在 EF 5 中跟踪SQL和缓存数据
- hihoCoder #1015 : KMP算法【KMP裸题,板子】
- 对X86汇编的理解与入门
- BZOJ 2748: [HAOI2012]音量调节【二维dp,枚举】
- POJ 3264 Balanced Lineup【线段树区间查询求最大值和最小值】
- HDU 2289 Cup【高精度,二分】
- BZOJ 1083: [SCOI2005]繁忙的都市【Kruscal最小生成树裸题】
- [快学Python3]二分查找[策略优化版本]
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 前端应该知道的web调试工具——whistle
- 最强大的 CSS 布局 —— Grid 布局
- SAP Spartacus ProductConnector和ProductService实现
- Sorted Adjacent Differences(CodeForces - 1339B)【思维+贪心】
- Redis 发布订阅,小功能大用处,真没那么废材!
- R语言实现生物序列的降维比对
- Tomcat NIO(9)-IO线程-Overall流程和关键类
- 有限元平面四边形等差单元python编程
- 动图演示:手撸堆栈的两种实现方法!
- [Go] 实战项目在线客服GO-FLY -在gin框架使用IP识别库转换IP为城市
- leetcode1552题解【二分+贪心】
- 这三年被分布式坑惨了,曝光十大坑
- 为什么删数据也提示空间不足呢?
- 前端踩坑系列《六》——让人又爱又恨的npm包
- docker运行Tomcat后访问首页报404(详细永久解决步骤)