编译环境:Visual Studio 2019
注:使用了Easyx 图形库。Easyx下载 Easyx官网
Easyx 图形库安装教程:https://blog.csdn.net/weixin_43919932/article/details/102996507
说明:此贪吃蛇游戏为第一版,使用了库中提供的简单的描线绘图功能所设计,不含资源包。可直接测试运行,贪吃蛇游戏 2.0在此基础上增加了贴图功能,界面相对部分优化。另外,为方便测试,在代码初始位置预留属性框中各属性参数均可自由调整
直接上代码:
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NON_CONFORMING_SWPRINTFS
#undef UNICODE
#undef _UNICODE
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
/*--------------------------------属 性---------------------------*/
#define WIDE 1200 /* 窗口大小 WIDE * HIGH像素 */
#define HIGH 700
#define FORM 200 /* 设置文字边框宽度 */
#define SIZE 40 //每节蛇的尺寸
#define LEN 100 //蛇的最长长度
#define COLOUR RGB(rand()%255,rand()%255,rand()%255) //彩色
static int speed = 100; //速度(控制刷新的时间间隔)
enum Direction { right = 77, left = 75, down = 80, up = 72, Esc = 27 };//枚举方向值
/*---------------------------资源-------------------------------------*/
//蛇
typedef struct _snake
{
int x[LEN]; //坐标—X
int y[LEN]; //坐标—Y
int len; //长度
int count; //分数
int direction; //方向
}Snake;
//食物
typedef struct _food
{
int x;
int y;
int flg;
}Food;
/************************************************************/
//变量
Snake snake; //蛇
Food food; //食物
//函数
void Form(); //文字提示框
void Init_Snake(); //初始化蛇
void Init_Food(); //初始化食物
void ShowSnake(); //贴图画蛇
void ShowFood(); //贴图画食物
void MoveSnake(); //蛇的移动
void KeyDown(); //控制
void EatFood(); //吃食物
int GameOver(); //游戏结束
void Form()
{
setlinecolor(BLACK); //画线颜色
setfillcolor(WHITE);
fillrectangle(0, 0, WIDE, HIGH - 1); //边框
setfillcolor(RGB(254, 236, 232)); //右侧文字框背景色
fillrectangle(WIDE - FORM, 0, WIDE, HIGH / 3); //上提示框,实时显示分数
fillrectangle(WIDE - FORM, HIGH / 3, WIDE, HIGH); //下提示框,操作手册
setbkmode(TRANSPARENT); //文字透明方式
settextcolor(LIGHTBLUE); //文字颜色
TCHAR str[3][50];
_stprintf(str[0], _T(" 得分:%4d 分"), snake.count);
_stprintf(str[1], _T(" 速度:%4d 级"), (100 - speed) / 20);
_stprintf(str[2], _T(" 长度:%4d 节"), snake.len);
for (int i = 0; i < 3; ++i)
{
outtextxy(WIDE - FORM + 10, i * 20 + 20, str[i]); //指定位置输出字符串
}
TCHAR str2[10][50];
_stprintf(str2[0], _T("提示:一枚果实10分 "));
_stprintf(str2[1], _T(" 撞到墙,或撞到自己"));
_stprintf(str2[2], _T(" 游戏游戏"));
_stprintf(str2[3], _T(" "));
_stprintf(str2[4], _T("按键:Esc : 强制退出游戏"));
_stprintf(str2[5], _T(" 1 : 加速 "));
_stprintf(str2[6], _T(" 0 : 减速"));
_stprintf(str2[7], _T(" 空格: 暂停"));
for (int i = 0; i < 8; i++)
{
outtextxy(WIDE - FORM + 10, HIGH / 3 + i * 20 + 20, str2[i]); //指定位置输出字符串
}
}
int main()
{
initgraph(WIDE, HIGH); //初始化窗口大小
setbkcolor(WHITE); //背景颜色
Init_Snake(); //初始化蛇
Init_Food(); //初始化食物
while (true)//强退
{
if (food.flg == 0)
{
Init_Food(); //初始化食物
}
cleardevice(); //刷新窗口
BeginBatchDraw(); //这个函数用于开始批量绘图。执行后,任何绘图操作都将暂时不输出到屏幕上,防止闪屏
Form(); //打印表框
if (_kbhit())
{
KeyDown(); //玩家控制蛇移动
}
ShowSnake(); //画蛇
ShowFood(); //画食物
EndBatchDraw(); // 结束批量绘制,并执行未完成的绘制任务
EatFood();
MoveSnake(); //蛇移动
if (GameOver() == 1) //游戏结束条件
{
break;
}
Sleep(speed); //控制速度
}
getchar();
closegraph();
return 0;
}
/*--------------------------蛇的功能函数--------------------------*/
//初始化蛇
void Init_Snake()
{
//初始化前三节蛇
snake.x[0] = SIZE * 2;
snake.y[0] = 0;
snake.x[1] = SIZE;
snake.y[1] = 0;
snake.x[2] = 0;
snake.y[2] = 0;
snake.len = 3;
snake.count = 0;
snake.direction = right; //默认向右
}
//初始化食物
void Init_Food()
{
srand((unsigned int)time(NULL));//随机种子
label:
int x = (WIDE - FORM) / SIZE; //预留 FORM 像素显示信息
int y = HIGH / SIZE;
food.x = rand() % x * SIZE; // *10 保证食物地址为整数,与蛇头比较
food.y = rand() % y * SIZE;
//检查食物是否在蛇身上
int i = 0;
while (i < snake.len)
{
if (food.x == snake.x[i] && food.y == snake.y[i])
{
goto label;
}
++i;
}
food.flg = 1;
}
//贴图画蛇
void ShowSnake()
{
for (int i = 0; i < snake.len; ++i)
{
setlinecolor(BLACK); //设置画线颜色
setfillcolor(GREEN); //设置填充颜色
fillrectangle(snake.x[i], snake.y[i], snake.x[i] + SIZE, snake.y[i] + SIZE);
/* 左上、右下坐标*/
}
}
//贴图画食物
void ShowFood()
{
setfillcolor(COLOUR); //设置填充颜色--彩色食物
fillrectangle(food.x, food.y, food.x + SIZE, food.y + SIZE);
}
//蛇的移动
void MoveSnake()
{
//把蛇的后一节坐标移动到前一节的坐标位置
for (int i = snake.len - 1; i > 0; --i)
{
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
}
//单独移动蛇头,根据蛇的方向移动
switch (snake.direction)
{
case right:
snake.x[0] += SIZE;
break;
case left:
snake.x[0] -= SIZE;
break;
case up:
snake.y[0] -= SIZE;
break;
case down:
snake.y[0] += SIZE;
break;
default:
break;
}
}
/*getch函数从控制台读取单个字符而不回显,函数不能去读取CTRL+C,当读取一个
功能键或方向键,函数必须调用两次(这就说明可以用这个函数去监控功能键
和方向键),第一次调用返回0或0xe0,第二次返回实际的键代码*/
//控制
void KeyDown()
{
char tmp = _getch(); //接受_getch()的第一个返回值
switch (tmp)
{
case '1': // 1 加速
if (speed > 20)
{
speed -= 20;
}
return;
break;
case '0': // 0 减速
if (speed < 200)
{
speed += 20;
}
return;
break;
default:
break;
}
char key = _getch(); //接受键盘键入的值
switch (key)
{
case right:
if (snake.direction != left) //不能相反方向移动
snake.direction = right;
break;
case left:
if (snake.direction != right)
snake.direction = left;
break;
case up:
if (snake.direction != down)
snake.direction = up;
break;
case down:
if (snake.direction != up)
snake.direction = down;
break;
case Esc: //强退
{
TCHAR s[] = _T("即将退出游戏,是(Y)/否(N)");
setfillcolor(LIGHTCYAN);
fillrectangle(0, 0, WIDE - FORM, HIGH);
setbkmode(TRANSPARENT); //文字透明方式
settextcolor(LIGHTBLUE); //文字颜色
outtextxy(WIDE * 3 / 10, HIGH / 2, s); //指定位置输出字符串
char ch = getchar();
if (ch == 'Y' || ch == 'y') exit(0);
}
break;
case ' ': //暂停
while (true)
{
if (_kbhit())
{
char ch = _getch();
if (_getch() == ' ') break;
}
}
break;
default:
break;
}
fflush(stdin);
}
//吃食物
void EatFood()
{
if (food.x == snake.x[0] && food.y == snake.y[0])
{
++snake.len;
snake.count += 10; //一个食物十分
food.flg = 0;
}
}
//死亡
int GameOver()
{
for (int i = 1; i < snake.len; i++)
{
//撞自己
if (snake.x[i] == snake.x[0] && snake.y[i] == snake.y[0])
{
TCHAR s[100];
_stprintf(s, _T("咬到自己了 GameOver!
您的分数为%d分"), snake.count);
setfillcolor(WHITE); //背景填充颜色
fillrectangle(0, 0, WIDE - FORM, HIGH);
setbkmode(TRANSPARENT); //文字透明方式
settextcolor(LIGHTBLUE); //文字颜色
outtextxy(WIDE * 2 / 10, HIGH / 2, s); //指定位置输出字符串
return 1;
}
//撞墙
else if (snake.x[i]<0 || snake.x[0]>WIDE - FORM - SIZE || //横坐标出界
snake.y[i]<0 || snake.y[0]>HIGH - SIZE) //纵坐标出界
{
TCHAR s[100];
_stprintf(s, _T("你撞墙了 GameOver!
您的分数为%d分"), snake.count);
setfillcolor(WHITE); //背景填充颜色
fillrectangle(0, 0, WIDE - FORM, HIGH);
setbkmode(TRANSPARENT); //文字透明方式
settextcolor(LIGHTBLUE); //文字颜色
outtextxy(WIDE * 2 / 10, HIGH / 2, s); //指定位置输出字符串
return 1;
}
//通关
else if (snake.len == LEN) //最长长度
{
TCHAR s[100];
_stprintf(s, _T("恭喜 通关 GameOver!
您的分数为%d分"), snake.count);
setfillcolor(WHITE); //背景填充颜色
fillrectangle(0, 0, WIDE - FORM, HIGH);
setbkmode(TRANSPARENT); //文字透明方式
settextcolor(LIGHTBLUE); //文字颜色
outtextxy(WIDE * 2 / 10, HIGH / 2, s); //指定位置输出字符串
return 1;
}
}
return 0;
}
效果如下: