接触编程有段时间了,一直想学习怎么去写个游戏来练练手。在看了B站上的教学终于可以自己试试怎么实现贪吃蛇这个游戏了。好了,废话不多说,我们来看看如何用EasyX库来实现贪吃蛇。
一、准备
- 工具vc++6.0
- 安装库文件
- EasyX库安装链接
- 可以安装任意版本,本人安装的是2018春分版
- 这是一个简单易学的一个图形库,相信对于大家学习来说应该不成问题
- 准备工作做好后接下来就得弄清楚游戏工作机制了
二、基本介绍
在这里我们需要明白EasyX库的基本知识,其次我们还有了解游戏的工作原理,不能盲目的直接写代码,需要一步步的思考,比如蛇是如何绘制、移动的;食物是怎么产生的;蛇吃了食物会怎样;死亡机制等等
EasyX库介绍
- 首先我们来讲讲EasyX库的坐标概念
- 物理坐标
- 简单来说,物理坐标就是以窗口的左上角为原点,以水平向右为x轴,竖直向下为y轴,以像素为单位
- 逻辑坐标
- 逻辑坐标和物理坐标是一一对应的,不过逻辑坐标是以点为单位
- 物理坐标
- 颜色概念
- EasyX库的预定义颜色常量如下:
常量 | 值 | 颜色 |
---|---|---|
BLACK | 0 | 黑 |
BULE | 0xAA0000 | 蓝 |
GREEN | 0x00AA00 | 绿 |
CYAN | 0xAAAA00 | 青 |
RED | 0x0000AA | 红 |
MAGENTA | 0xAA00AA | 紫 |
BROWN | 0x0055AA | 棕色 |
LIGHTGRAY | 0xAAAAAA | 浅灰 |
DARKGRAY | 0x555555 | 深灰 |
LIGHTBULE | 0xFF5555 | 亮蓝 |
LIGHTGREEN | 0x55FF55 | 亮绿 |
LIGHTCYAN | 0xFFFF55 | 亮青 |
LIGHTRED | 0x5555FF | 亮红 |
LIGHTMAGENTA | 0xFF55FF | 亮紫 |
YELLOW | 0x55FFFF | 黄 |
WHITE | 0xFFFFFF | 白 |
3.基本函数介绍
- initgraph(int width,int height,int flag=NULL):初始化绘图环境
- width:绘图环境的宽度
- height:绘图环境的高度
- flag:绘图环境的样式,默认为NULL
- cleardevice():用于清除屏幕内容
- setbkcolor(COLORREF color):设置背景颜色
- setfillcolor(COLORREF color):设置填充颜色
- setlinecolor(COLORREF color):设置当前画线颜色
- outtextxy(int x,int y,TCHAR c):用于在指定位置输出字符串
- x,y表示输出字符串的坐标值
- c表示待输出的字符
- fillroundrect(int left,int top,int right,int bottom,int ellipsewidth,int ellipseheight):绘制圆角矩形
- left:圆角矩形左部 x 坐标
- top:圆角矩形上部 y 坐标
- right:圆角矩形右部 x 坐标
- bottom:圆角矩形下部 y 坐标
- ellipsewidth:构成圆角矩形的圆角的椭圆的宽度
- ellipseheight:构成圆角矩形的圆角的椭圆的高度
工作原理
- 必须先包含头文件,才能运行
#include<graphics.h>
#include<time.h>
#include<stdlib.h>
#include<conio.h>
- 我们要有窗口才能绘制蛇和食物,因此可以用initgraph()函数来实现
- 其次我们要弄清楚如何来描述窗口位置,这里我们可以设置一个结构体Coor
struct Coor{
int x;
int y;
};
- 方向
enum Ch{ //枚举类型表示上下左右键的键值
up=72,
down=80,
left=75,
right=77
};
- 蛇也是有自己属性的结构体
struct Snake{
//蛇的属性
int n; //蛇当前节数,一节为一个正方形,n个正方形
struct Coor szb[500]; //snake的坐标,存放蛇的坐标,这里设置500,表示蛇能达到的最大长度为500
Ch ch; //蛇的方向
}snake; //变量
- 食物的结构体
struct Food{
struct Coor fzb; //食物坐标
int flag; //是否被吃
}food;
有了以上的结构体的定义,我们就可以设置函数来完成贪吃蛇的绘制、移动、食物的绘制以及死亡机制等等
- 函数内容如下
- InitSnake():包含窗口的初始化,初始化随机种子,初始化蛇的起始坐标
- DrawSnake():绘制蛇的每个节点
- MoveSnake():蛇的移动
- ChangeSnakeCh():通过键盘改变蛇的方向
- CoorFood():随机生成食物的坐标
- DrawFood():绘制食物样式
- EatFood():蛇吃掉食物后的变化
- KnockWall():撞墙死亡
- EatSelf():吃到自己死亡
void InitSnake(){
//初始化窗口
srand((unsigned int)time(NULL)); //产生随机种子
initgraph(200,200); //初始化200*200像素的绘图窗口
setbkcolor(GREEN); //设置背景颜色
//初始化蛇
//开始时蛇的节数为1,方向向右
snake.n=1;
snake.ch=right;
snake.szb[0].x=0;
snake.szb[0].y=0;
}
//绘制蛇,n节蛇
void DrawSnake(){
setlinecolor(GREEN); //设置蛇边缘的线条颜色
setfillcolor(RED); //设置蛇身的颜色
//遍历数组
for(int i=0;i<snake.n;i++){
fillrectangle(snake.szb[i].x,snake.szb[i].y,snake.szb[i].x+10,snake.szb[i].y+10); //根据蛇的当前长度,创建蛇身,这里设置一节蛇的大小为10*10个像素
}
}
- 关于蛇的移动其实很简单,只要将前面的节点坐标传递给后面的节点坐标,就能起到移动的效果
//蛇的移动
void MoveSnake(){
for(int i=snake.n-1;i>0;i--){
snake.szb[i].x=snake.szb[i-1].x;
snake.szb[i].y=snake.szb[i-1].y;
}
switch(snake.ch){
case up:
snake.szb[0].y-=10;
break;
case down:
snake.szb[0].y+=10;
break;
case left:
snake.szb[0].x-=10;
break;
case right:
snake.szb[0].x+=10;
break;
}
}
- 这里需要注意的是:蛇移动时的方向改变规则是在蛇向左/右移动时,蛇只能向上/下移动,同理对于蛇在向上/下移动的情况
//通过键盘控制
void ChangeSnakeCh(){
int move;
move=getch(); //获取键盘传递的字符
switch(move){
case right:
if(snake.ch!=left)
snake.ch=right;
break;
case left:
if(snake.ch!=right)
snake.ch=left;
break;
case up:
if(snake.ch!=down)
snake.ch=up;
break;
case down:
if(snake.ch!=up)
snake.ch=down;
break;
}
}
- 食物的产生与绘制
void CoorFood(){
food.fzb.x=rand()%20*10; //根据窗口像素来产生食物坐标
food.fzb.y=rand()%20*10;
food.flag=1; 1表示食物没被吃的状态,0表示已吃的状态
}
//绘制食物
void DrawFood(){
//绘制圆角矩形
setfillcolor(YELLOW);
fillroundrect(food.fzb.x,food.fzb.y,food.fzb.x+10,food.fzb.y+10,10,10);
}
//蛇吃食物
void EatFood(){
//判断蛇头和食物是否重合
if(snake.szb[0].x==food.fzb.x&&snake.szb[0].y==food.fzb.y){
snake.n++; //蛇身长度加1
food.flag=0; 食物标记为0表示已吃
}
}
- 死亡机制
//撞墙
int KnockWall(){
for(int i=0;i<snake.n;i++){
if(snake.szb[i].x>200||snake.szb[i].x<0||snake.szb[i].y>200||snake.szb[i].y<0){
//如果蛇头的坐标值超出窗口的坐标值,就返回错误
return 0;
}
}
}
//咬到自己
int EatSelf(){
for(int i=1;i<snake.n;i++){
if(snake.szb[0].x==snake.szb[i].x&&snake.szb[0].y==snake.szb[i].y){
//循环判断蛇头坐标是否与蛇身某部分重合,若重合则放回错误
return 0;
}
}
}
- 主函数
int main(){
InitSnake(); //初始化
while(1){
while(!kbhit()){ //未改变蛇的方向之前
if(food.flag==0){
CoorFood();
}
cleardevice(); //先清屏,才能保证之前绘制的蛇身不会显示出来
MoveSnake(); //先移动蛇的各个坐标
DrawFood(); //绘制食物
DrawSnake(); //再绘制蛇身
if(!KnockWall()||!EatSelf()) //死亡机制
break;
EatFood(); //吃掉食物后,蛇和食物的变化
Sleep(150); //设置蛇的移动速度
}
while(!KnockWall()||!EatSelf()){
outtextxy(100,100,"YOU DIED!"); //如果蛇吃到自己或撞墙则在窗口显示YOU DIED!
}
ChangeSnakeCh(); //通过键盘上下左右键来移动蛇
}
return 0;
}