基于EasyX库的贪吃蛇游戏——C语言实现

接触编程有段时间了,一直想学习怎么去写个游戏来练练手。在看了B站上的教学终于可以自己试试怎么实现贪吃蛇这个游戏了。好了,废话不多说,我们来看看如何用EasyX库来实现贪吃蛇。

一、准备

  • 工具vc++6.0
  • 安装库文件
    • EasyX库安装链接
    • 可以安装任意版本,本人安装的是2018春分版
    • 这是一个简单易学的一个图形库,相信对于大家学习来说应该不成问题
  • 准备工作做好后接下来就得弄清楚游戏工作机制了

二、基本介绍

在这里我们需要明白EasyX库的基本知识,其次我们还有了解游戏的工作原理,不能盲目的直接写代码,需要一步步的思考,比如蛇是如何绘制、移动的;食物是怎么产生的;蛇吃了食物会怎样;死亡机制等等

EasyX库介绍

  1. 首先我们来讲讲EasyX库的坐标概念
    • 物理坐标
      • 简单来说,物理坐标就是以窗口的左上角为原点,以水平向右为x轴,竖直向下为y轴,以像素为单位
    • 逻辑坐标
      • 逻辑坐标和物理坐标是一一对应的,不过逻辑坐标是以点为单位
  2. 颜色概念
  • 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;
}
上一篇:在自己的网站上实现QQ授权登录


下一篇:认识SQLServer索引以及单列索引和多列索引的不同