相信许多前行在编程学习之路的同学们都跟我一样有自己写游戏的小梦想。在之前的探索和学习中,我们已经接触过了用诸如Construct2这样的“黑箱”开发平台来创造自己的游戏,但不是自己打出来的代码始终觉得缺少一点感觉。经过半个多学期的编程技术和编程思想的学习,运用较为基本的C语言知识和自顶向下的思想方法,我们已经有能力自己完成一个经典的字符游戏:贪吃蛇。
是指没有专门的多媒体元素构成游戏的可视化界面,而是全靠计算机屏幕原生的如字母、数字、符号@#¥%&*等作为图像单位来表示游戏中的各种元素的游戏。不要小看字符游戏,单凭有限的字符,也可以实现元素的多种多样和游戏的丰富性:字符游戏大军中不仅有十分常见的经典游戏如贪吃蛇,更有复杂如RPG类的游戏。在这次的实践中,我们就将用字符完成贪吃蛇游戏的开发实现。
贪吃蛇是大家都很熟悉的游戏了,在此不必过多赘述,便说说在字符版贪吃蛇的设计中的基本游戏框架。首先,初阶版本中的贪吃蛇在玩家没有键入操作时不会自己移动,玩家可通过WSAD键分别控制由蛇头牵动的上下左右移动,初阶游戏中蛇的活动场地为10*10方阵(由于程序运行窗内字体布局设置看起来比较“瘦高”),场地中会有随机食物生成,吃到食物时马上会产生另一个食物,同时蛇变长一节,蛇头撞到身体或墙壁时游戏结束。
一个简介明晰的程序头便可以让人获取大部分程序信息。自己的程序虽然还达不到这样的水平,但姑且用程序头来串联起在游戏设计中我的基本思路。源代码可见GitHub中我的源码。
#include
#include
#include
#define blank ' '
#define wall '*'
#define food '$'
#define head 'H'
#define body 'X'
#define maxlength 99
void printer(void);//游戏界面打印
void move(int x, int y);//蛇动作实现。x在-1,1,0时分别表示左走,右走,不走;y在-1,1,0时分别表示下走,上走,不走
void refresh(void);//更新地图情况
void creatfood(void);//随机生成食物
int locationx[maxlength] = { 1,1,1,1,1 },
locationy[maxlength] = { 1,2,3,4,5 };//定义数组存储蛇躯体在地图上坐标
int length = 5;//储存蛇当前长度
int lastx, lasty;//储存蛇尾原坐标
int foodx, foody;//储存食物坐标
int map[12][12] = { { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 },
{ -1,1,1,1,1,2,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,0,0,0,0,0,0,0,0,0,0,-1 },
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 } };
//地图:-1为障碍,0为空,1为蛇身,2为蛇头,3为食物
int flag = 1;//表示游戏状态。1表示可以继续,0表示游戏结束
对于游戏全局,用flag来控制游戏的进行或终结,初始化flag=1,程序主体在while(flag)的block中运行,即每一步都会对flag的值进行判断,在负责蛇移动的子函数中就有对当前情况是否游戏结束的判定:当判定蛇在某步操作后将撞到自己或障碍时,flag的值将变为0,输出Game Over字样,程序停止运行。
用map数组存储当前地图上蛇身体的分布和食物所在情况,用locationx[],locationy[],length等,存储蛇长,蛇身坐标等基本信息,在负责处理移动情况的板块中对其进行同步的改变(move),更新(refresh),并完成打印(printer),便可以实现蛇移动的“实况”。
因此思路其实非常常规,故不对更具体的实现多做细化解释。下面我们来介绍一下一些做贪吃蛇这款游戏中的特殊处理技巧。
直接用符号作为函数中的操作值,将地图用字符数组存起来确实会方便程序编写和打印时的简便。但设置常量和数字数组是为了以后游戏元素调整时的方便,因整个游戏界面的呈现,即打印部分的工作都集成在了printer子程序上,其中又均由已定义的常量作为操作值,所以若以后要改蛇头蛇身和障碍物等字符表示时,只需要统一在#define段对表示各个元素的字符进行修改即可,十分方便游戏的变形。
比如我们可以非常简便地(很丑地)重新定义游戏元素:
刚着手时我也有这样的问题,运行窗口只有简单的输出打印,如何实现平常游戏看到的动态效果呢?
清屏函数system(“cls”)和无需回车的字符读取函数getch(),两举解决了我的困惑。
顾名思义,system(“cls”)清屏函数实现了输出窗口的清空,以方便我们每次打印出地图实时情况时窗口已经被初始化为空白,加之计算机运行速度快,人有一定的视觉暂留,清空配合打印,看起来就像蛇动起来了一样。另外,我们可以用getch()实时读取来自键盘的输入,即每次键盘键入WSAD其中之一计算机就可以马上识别操作并完成移动计算,打印出移动后蛇和地图的状态。
来看看我们的字符版初阶贪吃蛇的游戏效果吧:
以上便是初阶贪吃蛇游戏的算法设计实现粗略流程,后续还将推出对更完整的贪吃蛇和“智能蛇”的学习实践分享。
谢谢阅读!