欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于c语言和easyx库的贪吃蛇程序的实现

程序员文章站 2022-04-07 12:37:06
...

```基于c语言和easyx库的贪吃蛇程序的实现

大学课程中所编写的贪吃蛇游戏

游戏界面截图
基于c语言和easyx库的贪吃蛇程序的实现

/********************************************************************************

  • @File name: Snake
  • @Description:基于c语言和easyx库的贪吃蛇程序的实现
  • @Author: Sky_codes
  • @Version: 0.51
  • @Date: 2019-12-01
    ********************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>//easyx图形库
#include<mmsystem.h>//媒体库
#include<conio.h>
#include<Windows.h>
#include<time.h>
#pragma comment (lib,“Winmm.lib”)

#define INIT_X 800//初始化界面宽度
#define INIT_Y 480//初始化界面高度
#define SNAKE_LEN 3 //初始化小蛇长度

/声明结构体/
typedef enum ch //枚举 按键的数值
{
up = 119, //向上 W
down = 115,//向下 S
left = 97, //向左 A
right = 100,//向右 D
esc = 27, //退出 ESC
addSpeed = 113,//加速 Q
subSpeed = 101,//减速 E
stop = 32 //暂停 space空格
}Ch;

struct coor //坐标
{
int x; int y;//x、y坐标数值
};

struct food //食物结构体
{
struct coor fcr;//食物的坐标
int flag;//判断食物是否被吃,被吃后置反
}Food;

struct snake //小蛇结构体
{
struct coor scr[100];//蛇身长度限制
int len;//小蛇实际长度
Ch ch;//小蛇当前的朝向
int score;//得分
int speed;//速度

}Snake;

/声明函数/
void playMusic();/播放背景音乐/
void initGame();//初始化游戏界面
void initWelcome();//初始化进入页面
void playWhile();//游戏中循环函数
void initSnake();//初始化小蛇
void snakeMove(); //小蛇的移动
void snakeDraw();//画出小蛇
void getKey();//得到键值
void randFood();//随机食物
void foodDraw();//画出食物
void eatFood();//吃到食物
int eatSelforWall();//吃到自己或者撞墙
void getFlagKey();//按键去除移动其他按键的功能实现
void gameEnd();//死亡后是否结束游戏或者再开始
void gameOver(); //游戏结束
void againInit();//死亡后再进行游戏,进行初始化
void display_msg();//展示信息

/声明所需各个需求变量/
char scroe_s[100] = {‘0’};//分转换字符数组中间变量
char font[2][10] = { “宋体”,“黑体” };//字体选择
char goder[20] = “【作者】SKY”;//欢迎界面信息
char vision[20] = “【版本】0.51”;//欢迎界面信息
char gameName[20] = “C—贪吃蛇”;//欢迎界面标题
char songBgm[2][30] = { “open BGM.mp3 alias ACE” ,“play ACE repeat” };//背景音乐
char speak[5][20] = { “【得分】”,"【速度】","【长度】" };//游戏界面的数据展示
char speak2[5][20] = { “【最高得分】”,"【最快速度】","【最佳长度】" };//游戏界面的数据展示
int flagKey = 0;//判断除去方向按键其他按键的选择标识符
int speed = 100;//小蛇速度
int maxScore = 0, maxSpeed = 100, maxLen = 3;//保留最佳成绩

/*******************************************************
*

  • Function name :main
  • Description : 程序主函数
  • Return :0 正常退出
    **********************************************************/

int main()
{
playMusic();//播放音乐

initWelcome();//欢迎界面
system("pause");//用户按任意键进入游戏
cleardevice();//清除界面
closegraph();//关闭此画布

initgraph(INIT_X, INIT_Y);//初始化游戏窗口大小900*600
initGame();//初始化画布
initSnake();//初始化小蛇
Food.flag = 1;//置食物标识符为1,去生成第一个随即食物*/

playWhile();//游戏进行期间

return 0;

}

/*******************************************************
*

  • Function name :initWelcome
  • Description : 初始化进入页面,向玩家展示操作规则
  • Return :无
    **********************************************************/

void initWelcome()
{

initgraph(INIT_X,INIT_Y);//建立画布
setfillcolor(RGB(255,200, 215));//调节画布颜色

solidrectangle(0, 0, INIT_X,INIT_Y/2);//提取画布上半部矩形区域
setcolor(RGB(120, 200, 150));
settextstyle(40, 20, font[0]);//设置字体属性
setbkmode(TRANSPARENT);//设置背景为透明

outtextxy(110, 50, gameName);//在具体位置输出相关文字
settextstyle(20, 10, font[1]);
outtextxy(110, 100, goder);
outtextxy(110, 130, vision);

setfillcolor(RGB(255,200, 215));//调节画布颜色
solidrectangle(0, INIT_Y/2, INIT_X, INIT_Y);//提取画布下半部矩形区域ju

RECT r = {0,INIT_Y/2,400,INIT_Y};//得到在下半部分矩形中的部分区域
settextcolor(BLACK);//设置字体颜色
settextstyle(15, 0, "仿宋");//设置字体大小、风格
drawtext(_T("【功能按键】\n W->上 S->下 \n A->左 D->右\n Q->加速 E->减速\n 空格->暂停 ESC->退出\n"), &r, DT_LEFT);//在r矩阵中展示的语句

RECT r2= { 0,INIT_Y/2+100,400,INIT_Y};
settextcolor(BLACK);
settextstyle(20, 0, "仿宋");//设置字体大小、风格
drawtext(_T("【提示】\n此游戏在英文输入法下进行操控\n按任意键进入游戏\n"), &r2, DT_LEFT);//展示的语句

}

/*******************************************************
*

  • Function name :initGame
  • Description : 初始化游戏界面,在界面中设置游戏进程中向玩家展示的语句
  • Return :无
    **********************************************************/

void initGame()
{
/裁剪得到非游戏区域/
setfillcolor(0xe6b8af);//设置填充颜色
solidrectangle(600, 0, 800, 480);//绘制矩形在裁剪区
//setbkcolor(RGB(200, 150, 120));
setcolor(RED);//设置颜色

settextstyle(30, 15, font[0]);//设置字体大小、风格
setbkmode(TRANSPARENT);//设置背景为透明
outtextxy(625, 50, gameName);//设置游戏名称

/*提示语句区域*/
RECT r = { 625, 100, 780, 200 };//创建一个矩形放置语句
settextstyle(15, 0, font[1]);//设置字体大小、风格
drawtext(_T("简单的贪吃蛇小游戏\n祝你好运\n"), &r, DT_CENTER);//展示的语句
sprintf(scroe_s, "%d", Snake.score);
outtextxy(600, 150, speak[0]);
outtextxy(680, 150, scroe_s);
sprintf(scroe_s, "%d", Snake.speed);
outtextxy(600, 180, speak[1]);
outtextxy(680, 180, scroe_s);
sprintf(scroe_s, "%d", Snake.len + 1);
outtextxy(600, 210, speak[2]);
outtextxy(680, 210, scroe_s);

RECT r2 = { 600, 240, 780, 480 };//创建一个矩形放置语句
settextstyle(15, 0, font[1]);//设置字体大小、风格
drawtext(_T("【功能按键】\n W->上 S->下 \n A->左 D->右\n Q->加速 E->减速\n 空格->暂停 ESC->退出\n"), &r2, DT_LEFT);//展示的语句

/*游戏区域的属性设置,背景颜色、区域大小*/
setfillcolor(0xf4cccc);
solidrectangle(0, 0, 600, 480);//绘制矩形

}

/*******************************************************
*

  • Function name :againInit
  • Description : 小蛇死亡后再进行游戏,进行相关属性的初始化
  • Return :无
    *********************************************************/
    void againInit()
    {
    initGame();//初始化画布
    initSnake();//初始化小蛇
    Food.flag = 1;//置食物标识符为1,去生成第一个随即食物
    /
    playWhile();//进入游戏

}

/*******************************************************
*

  • Function name :playWhile
  • Description : 玩家游戏中循环函数,在玩家游戏时做出相应的动作响应玩家
  • Return :无
    **********************************************************/
    void playWhile()
    {
    while (1)
    {
    while (!_kbhit())//判断是否有按键输入
    {
    snakeMove();//小蛇的移动
    eatFood();//判断是否吃到食物
    if (Food.flag == 1)//标识符为1
    {
    randFood(); //生成随机食物坐标
    }
    if (eatSelforWall())//函数返回值为1,游戏结束
    {
    gameEnd();//死亡后是否结束游戏或者再开始
    }
    foodDraw();//画出食物
    Sleep(speed);//延时
    //cleardevice();//以背景色清空画布
    //initGame();
    display_msg();//展示此时小蛇的属性信息
    }
    getKey();//玩家键值的输入
    }

}

/*******************************************************
*

  • Function name :display_msg
  • Description : 玩家游戏过程中,对小蛇属性的及时的刷新展示
  • Parameter :无
  • Return :无
    **********************************************************/
    void display_msg()
    {
    /写入一个新的矩形,覆盖之前的矩形,再写入小蛇的属性数据/
    setfillcolor(0x90b1e8);
    solidrectangle(600,150,800,230);
    settextcolor(BLACK);
    sprintf(scroe_s, “%d”, Snake.score);
    outtextxy(600, 150, speak[0]);
    outtextxy(680, 150, scroe_s);
    sprintf(scroe_s, “%d”, Snake.speed);
    outtextxy(600, 180, speak[1]);
    outtextxy(680, 180, scroe_s);
    sprintf(scroe_s, “%d”, Snake.len + 1);
    outtextxy(600, 210, speak[2]);
    outtextxy(680, 210, scroe_s);

}

/*******************************************************
*

  • Function name :initSnake
  • Description :对小蛇的各项属性进行初始化
  • Parameter :无
  • Return :无
    **********************************************************/
    void initSnake()
    {
    //设置小蛇的属性
    setcolor(WHITE);
    setfillcolor(WHITE);
    fillroundrect(200, 100, 210, 110,8,6);
    Snake.len = SNAKE_LEN;
    Snake.scr[0].x = 200;
    Snake.scr[0].y = 100;
    Snake.ch = down;
    Snake.score = 0;
    Snake.speed = 100;
    }

/*******************************************************
*

  • Function name :snakeMove

  • Description : 小蛇移动时,方向的确定和改变小蛇每个关节的坐标

  •   			并且将蛇尾消影
    
  • Parameter :无

  • Return :无
    **********************************************************/
    void snakeMove()
    {
    int i;

    setfillcolor(0xf4cccc); //对蛇尾进行消影处理
    //fillrectangle(Snake.scr[Snake.len].x,Snake.scr[Snake.len].y, Snake.scr[Snake.len].x+10, Snake.scr[Snake.len].y+10 );
    solidrectangle(Snake.scr[Snake.len].x,Snake.scr[Snake.len].y, Snake.scr[Snake.len].x+10, Snake.scr[Snake.len].y+10 );

    for (i = Snake.len; i > 0; i–) //改变小蛇的各个节位坐标,使之移动
    {
    Snake.scr[i].x = Snake.scr[i - 1].x;
    Snake.scr[i].y = Snake.scr[i - 1].y;
    }

    switch (Snake.ch) //判断小蛇此时的方向,使之相应的坐标变化
    {
    case up: Snake.scr[0].y -= 10;
    break;
    case down:Snake.scr[0].y += 10;
    break;
    case left:Snake.scr[0].x -= 10;
    break;
    case right:Snake.scr[0].x += 10;
    break;
    }
    snakeDraw();//画出改变后的小蛇

}

/*******************************************************
*

  • Function name :snakeDraw
  • Description : 画出位置改变后的小蛇,并随机改变小蛇每节的颜色
  • Return :无
    **********************************************************/
    void snakeDraw()
    {
    srand((unsigned)time(NULL));
    int i,color;
    for (i = Snake.len; i >= 0; i–)
    {
    color = rand()%4; //随机选择设置小蛇每节颜色
    switch(color)
    {
    case 0:setfillcolor(RGB(30, 144, 255)); break;
    case 1:setfillcolor(RGB(245, 5, 90)); break;
    case 2:setfillcolor(RGB(125, 62, 74)); break;
    case 3:setfillcolor(RGB(20, 7, 9)); break;
    }
    //fillrectangle(Snake.scr[i].x, Snake.scr[i].y, Snake.scr[i].x + 10, Snake.scr[i].y + 10);
    fillroundrect(Snake.scr[i].x, Snake.scr[i].y, Snake.scr[i].x + 10, Snake.scr[i].y + 10,8,6);
    }
    }

/*******************************************************
*

  • Function name :getKey

  • Description : 对于玩家输入的按键处理,进行相应的响应

  • Parameter :无

  • Return :无
    **********************************************************/
    void getKey()
    {
    int getkey;
    getkey = _getch();//此处使用了c++改变后的_getch()语句,得到玩家输入的键值,无需敲打回车

    switch (getkey)//判断玩家输入的键值,如果与小蛇此时的方向相反,不给予响应
    {
    case up: if (Snake.ch != down) Snake.ch = up;
    break;
    case down:if (Snake.ch != up) Snake.ch = down;
    break;
    case left:if (Snake.ch != right) Snake.ch = left;
    break;
    case right:if (Snake.ch != left) Snake.ch = right;
    break;
    case esc:flagKey = 1;
    break;
    case addSpeed:flagKey = 2;
    break;
    case subSpeed:flagKey = 3;
    break;
    case stop:flagKey = 4;
    break;
    }
    getFlagKey();//除去方向按键其他功能性按键的实现
    }

/*******************************************************
*

  • Function name :randFood
  • Description : 随机生成食物坐标
  • Parameter :无
  • Return :函数返回值的说明
    **********************************************************/
    void randFood()
    {
    srand((unsigned)time(NULL));//种子
    //得到的随机数应为10的倍数
    Food.fcr.x = rand() % (600 / 10) * 10;
    Food.fcr.y = rand() % (480 / 10) * 10;
    Food.flag = 1;//重新将食物标识符设为1,表示已生成一个食物

}

/*******************************************************
*

  • Function name :foodDraw
  • Description : 在画布中画出食物
  • Parameter :无
  • Return :函数返回值的说明
    **********************************************************/
    void foodDraw()
    {
    //cleardevice();
    fillrectangle(Food.fcr.x, Food.fcr.y, Food.fcr.x + 10, Food.fcr.y + 10);//画出食物
    Food.flag = 0;//食物标识符置反
    }

/*******************************************************
*

  • Function name :函数名称
  • Description : 小蛇吃到食物进行蛇身的加长和得分的增加和食物的标识符变化
  • Parameter :无
  • Return :无
    **********************************************************/
    void eatFood()
    {
    if (Snake.scr[0].x == Food.fcr.x && Snake.scr[0].y == Food.fcr.y)//蛇头与食物相遇的判断
    {
    Snake.len++;//小蛇长度加1
    Snake.score += 10;//增加得分
    Food.flag = 1;//置食物标识符
    }
    }

/*******************************************************
*

  • Function name :eatSelforWall
  • Description : 判断是否吃到自己或者撞墙
  • Return :返回1 撞墙或者蛇头与自身相遇 返回0 游戏继续
    **********************************************************/
    int eatSelforWall()
    {
    int i;//循环使用变量
    //是否撞墙
    if (Snake.scr[0].x == 0 || Snake.scr[0].y == 480 || Snake.scr[0].x == 600 || Snake.scr[0].y == 0)
    return 1;
    //是否吃到自己
    for (i = 1; i < Snake.len; i++)
    {
    if (Snake.scr[0].x == Snake.scr[i].x && Snake.scr[0].y == Snake.scr[i].y)
    return 1;
    }
    return 0;
    }

/*******************************************************
*

  • Function name :getFlagKey

  • Description : 除去方向按键其他功能性按键的实现

  • Return :无
    **********************************************************/
    void getFlagKey()
    {
    if (flagKey == 1) //退出 ESC
    {
    flagKey = 0; closegraph(); exit(0);
    }

    else if (flagKey == 2) //加速 Q
    {
    flagKey = 0; speed -= 10; Snake.speed += 10;
    if (speed <= 50) { speed = 50; Snake.speed = 150; }
    }

    else if (flagKey == 3)//减速 E
    {
    flagKey = 0; speed += 10; Snake.speed -= 10;
    if (speed >= 150) { speed = 150; Snake.speed = 50; }
    }

    else if (flagKey == 4)//space空格
    { flagKey = 0; system(“pause”); }
    }

/*******************************************************
*

  • Function name :gameEnd

  • Description : 死亡后是否结束游戏或者再开始

  • Parameter :无

  • Return :无
    **********************************************************/
    void gameEnd()
    {
    /得到每次游戏后的各项指标的最大值/
    maxScore = maxScore > Snake.score ? maxScore : Snake.score;
    maxLen = maxLen > Snake.score ? maxLen : Snake.len;
    maxSpeed = maxSpeed > Snake.speed ? maxSpeed : Snake.speed;

    /输出提示信息/
    RECT r3 = { 100,100,400,300 };
    setbkmode(TRANSPARENT);//设置背景为透明
    settextcolor(WHITE);
    settextstyle(50, 25, “黑体”);
    drawtext(_T(“游 戏 结 束”), &r3, DT_CENTER);

    RECT r4 = { 100,300,400,600 };

    settextstyle(30, 15, “仿宋”);
    drawtext(_T("【双击】\nE【再来一局】\nQ【退出游戏】\n"),&r4,DT_LEFT);
    system(“pause”);
    int getKey;
    getKey = _getch();//得到玩家键值,反馈相应信息
    switch (getKey)
    {

      case 113: gameOver();//退出
      	break;
      
      case 101: againInit();//再来一局
      	break;
    

    }

}

/*******************************************************
*

  • Function name :gameOver

  • Description : 游戏结束函数

  • Return :无
    **********************************************************/
    void gameOver()
    {

    //system(“pause”);
    cleardevice();//清空并关闭画布
    closegraph();
    initgraph(500,200);//建立结束画布

    int x=400, y=20, speed=0,r=50,flag=0;//设置跳动小球的参数
    while (1)/输出本次游戏的最佳成绩和小球弹跳动画/
    {

      setfillcolor(RGB(47, 79, 79));
      settextstyle(40, 20, font[0]);
      outtextxy(120, 50, "游戏结束");
      settextcolor(RGB(255, 255, 224));
      settextstyle(20, 10, font[1]);
      sprintf(scroe_s, "%d", maxScore);
      outtextxy(80, 100, speak2[0]);
      outtextxy(200, 100, scroe_s);
      sprintf(scroe_s, "%d", maxSpeed);
      outtextxy(80, 140, speak2[1]);
      outtextxy(200, 140, scroe_s);
      sprintf(scroe_s, "%d", maxLen+1);
      outtextxy(80, 180, speak2[2]);
      outtextxy(200, 180, scroe_s);
    
    
      /*小圆运动动画*/
      circle(x, y, 30);
      Sleep(50);
      if (y > 180) { flag = 1; speed = -speed; }
      if (y < 20) { flag = 0; speed = -speed; }
      printf("%d %d\n", speed,y);
    
      y = y + speed++;
      if (y < 12) y = 20;
      cleardevice();
    

    }

}

/*******************************************************
*

  • Function name :playMusic
  • Description : 循环播放背景音乐
  • Return :无
    **********************************************************/
    void playMusic()
    {
    //调用函数,播放音乐
    mciSendString(songBgm[0], NULL, 0, NULL);
    mciSendString(songBgm[1], NULL, 0, NULL);
    }