一时心血来潮写的贪吃蛇,还有很多值得优化的地方,但实在不想改了,发出来给大家看看吧
本文会介绍一些构建贪吃蛇关键的函数,在本文末尾有源码
一些头函数
#include<iostream>
#include<easyx.h>
#include<conio.h>//_kbhit
#include<time.h>//Sleep
#include<stdlib.h>//随机数
结构体构造(类)
因为我写了双人游戏,所以这里的结构体有p1和p2
结构体里面很多内容我还没实现,因为一开始想的太过于宏大了
可以去掉那些不用的东西
struct food
{
int foodx[3], foody[3];
int flag[3];//食物存在=1
char color[6];
int number;//存在个数
};
typedef struct Point//这个是坐标
{
int x, y;
}point;
class player1
{
public:
int snakesize;
int speed;
int diret;
int attact;//可攻击次数
point attact1;//攻击物的坐标
point body1[maxsize];
};
class player2
{
public:
int speed;
int snakesize;
int diret;
int attact;//攻击
point body2[maxsize];
};
player1 p1;
player2 p2;
游戏绘制
void drawgame()
{
BeginBatchDraw();
setbkcolor(GREEN);
cleardevice();
rectangle(0, 0, 1091, 613);//边框
setlinecolor(RED);
for (int i = 0;i < p1.snakesize;i++)
{
rectangle(p1.body1[i].x,p1.body1[i].y, p1.body1[i].x + movesize,p1.body1[i].y + movesize);
}
for (int i = 0;i < p2.snakesize;i++)
{
rectangle(p2.body2[i].x, p2.body2[i].y, p2.body2[i].x + movesize, p2.body2[i].y + movesize);
}
//food
eatfood();
//攻击
EndBatchDraw();
}
按键控制
void key()
{
if (_kbhit())
{
switch (_getch())
{
case ' ':
while (1)
{
if (_getch() == ' ')
return;
}
break;
case 87:
if (p1.diret != down) {
p1.diret = up;
p1.body1[0].y -= p1.speed;
}
break;
case 83:
if (p1.diret != up) {
p1.diret = down;
p1.body1[0].y += p1.speed;
}
break;
case 65:
if (p1.diret != right) {
p1.diret = left;
p1.body1[0].x -= p1.speed;
}
break;
case 68:
if (p1.diret != left) {
p1.diret = right;
p1.body1[0].x += p1.speed;
}
break;
case 'i':
case 72://百度查的是上
if (p2.diret != down) {
p2.diret = up;
p2.body2[0].y -= p2.speed;
std::cout << "hello \n\n\n" << std::endl;
}
break;
case 'k':
case 80://百度查的是下
if (p2.diret != up) {
p2.diret = down;
p2.body2[0].y += p2.speed;
}
break;
case 'j':
case 75://左
if (p2.diret != right) {
p2.diret = left;
p2.body2[0].x -= p2.speed;
}
break;
case 'l':
case 77://右
if (p2.diret != left) {
p2.diret = right;
p2.body2[0].x += p2.speed;
}
break;
case '0':
gamemenu();
break;
}
}
}
蛇的移动
void movesnake()
{
for (int i =p1.snakesize-1;i >0;i--)
{
p1.body1[i].x = p1.body1[i-1].x;
p1.body1[i].y = p1.body1[i-1].y;
}
for (int i = p2.snakesize - 1;i > 0;i--)
{
p2.body2[i].x = p2.body2[i - 1].x;
p2.body2[i].y = p2.body2[i - 1].y;
}
switch (p1.diret)
{
case up:
p1.body1[0].y-=movesize;
break;
case down:
p1.body1[0].y+=movesize;
break;
case left:
p1.body1[0].x-=movesize;
break;
case right:
p1.body1[0].x+=movesize;
break;
}
switch (p2.diret)
{
case up:
p2.body2[0].y -= movesize;
break;
case down:
p2.body2[0].y += movesize;
break;
case left:
p2.body2[0].x -= movesize;
break;
case right:
p2.body2[0].x += movesize;
break;
}
}
速度控制
使用sleep函数速度调快之后总是有点小小的卡顿,所以这里使用的是一个函数
int timer(int duration, int id)//替代sleep函数
{
static int starttime[10];
int endtime = clock();//返回当前程序运行时间(毫秒)
if (endtime - starttime[id] > duration)
{
starttime[id] = endtime;
return 1;
}
return 0;
}
/*
只需要在移动蛇那个函数那里加上
if (timer(250, 0))
{
moves();
}
这里250可改 进而调整速度
*/
按钮绘制
这里可以再添加一个变量去改变背景颜色
void button(int x, int y, int w, int h, const char* text)//按钮绘制
{
setbkmode(TRANSPARENT);
setfillcolor(BROWN);
fillroundrect(x, y, x + w, y + h, 10, 10);
settextstyle(30, 0, "黑体");
//报错 重载函数 在属性里面使用多字符节
char text_[50] = "button";
strcpy_s(text_, text);
int tx = x + (w - textwidth(text)) / 2;
int ty = y + (h - textheight(text)) / 2;
outtextxy(tx, ty, text);
}
完整代码
这个还有很多待完善的地方,后面的双人对战实在写不下去了,可以删掉,这里我直接放全部的(包括没写完的)代码,你也可以根据需要自己删除更改一部分
使用vs2022版本运行,请先前往官网安装easyx
如果因为easyx报错,请在属性里改为使用多字符集
#include<iostream>
#include<easyx.h>
#include<conio.h>
#include<time.h>
#include<stdlib.h>//随机数
#define maxsize 50
#define movesize 5//方格长度,每次移动也是5
void drawgame();//游戏所有绘制的图形
void key();//按键控制
void movesnake();//蛇的移动
void initgame();//初始化一些参数
void gameover();//游戏结束画面
int timer(int duration, int id);//代替Sleep函数更流畅
//传过去间隔时间
void button(int x, int y, int w, int h, const char* text);//写的生成按钮函数
void gamemenu();//菜单界面的绘制
void twoplayergame();
void singleplayergame();
void initgame();
void drawhelp();
void battlemode();
struct food
{
int foodx[3], foody[3];
int flag[3];//食物存在=1
char color[6];
int number;//存在个数
};
food f;
enum Diret
{
down, up, left, right
};
typedef struct Point
{
int x, y;
}point;
class player1
{
public:
int snakesize;
int speed;
int diret;
int attact;//可攻击次数
point attact1;//攻击物的坐标
point body1[maxsize];
};
class player2
{
public:
int speed;
int snakesize;
int diret;
int attact;//攻击
point body2[maxsize];
};
player1 p1;
player2 p2;
void initgame()
{
p1.speed = 0;
p1.snakesize = 3;
p1.diret = right;
for (int i = 0; i < p1.snakesize; i++)
{
p1.body1[i].x = 66 + movesize * i;
p1.body1[i].y = 66;
}
p2.speed = 0;
p2.snakesize = 3;
p2.diret = left;
for (int i = 0; i < 3; i++)
{
p2.body2[i].x = 266 + movesize * i;
p2.body2[i].y = 266;
}
}
void eatfood()
{
for (int i = 0; i < 3; i++)
{
if (f.flag[i] == 1 && p1.body1[0].x > (f.foodx[i] - movesize - 1) && p1.body1[0].x<(f.foodx[i] + movesize + 1) && p1.body1[0].y>(f.foody[i] - movesize - 1) && p1.body1[0].y < (f.foody[i] + movesize + 1))
{
p1.snakesize++;
f.number--;
f.flag[i] = 0;
}
if (f.flag[i] == 1 && p2.body2[0].x > (f.foodx[i] - movesize - 1) && p2.body2[0].x<(f.foodx[i] + movesize + 1) && p2.body2[0].y>(f.foody[i] - movesize - 1) && p2.body2[0].y < (f.foody[i] + movesize + 1))
{
p2.snakesize++;
f.number--;
f.flag[i] = 0;
}
if (f.flag[i] == 0)
{
f.foodx[i] = rand() % 1091;
f.foody[i] = rand() % 613;
f.flag[i] = 1;
}
if (f.flag[i] == 1)
{
fillrectangle(f.foodx[i], f.foody[i], f.foodx[i] + movesize, f.foody[i] + movesize);
}
}
/*
//1玩家碰到三个食物增长
if (f.flag[0] == 1 && p1.body1[0].x > (f.foodx[0] - movesize - 1) && p1.body1[0].x<(f.foodx[0] + movesize + 1) && p1.body1[0].y>(f.foody[0] - movesize - 1) && p1.body1[0].y < (f.foody[0] + movesize + 1))
{
p1.snakesize++;
f.number--;
f.flag[0] = 0;
}
if( f.flag[1] == 1 && p1.body1[0].x > (f.foodx[1] - movesize - 1) && p1.body1[0].x<(f.foodx[1] + movesize + 1) && p1.body1[0].y>(f.foody[1] - movesize - 1) && p1.body1[0].y < (f.foody[1] + movesize + 1))
{
p1.snakesize++;
f.number--;
f.flag[1] = 0;
}
if (f.flag[2] == 1 && p1.body1[0].x > (f.foodx[2] - movesize - 1) && p1.body1[0].x<(f.foodx[2] + movesize + 1) && p1.body1[0].y>(f.foody[2] - movesize - 1) && p1.body1[0].y < (f.foody[2] + movesize + 1))
{
p1.snakesize++;
f.number--;
f.flag[2] = 0;
}//
//玩家2碰到三个食物增长
if (f.flag[0] == 1 && p2.body2[0].x > (f.foodx[0] - movesize - 1) && p2.body2[0].x<(f.foodx[0] + movesize + 1) && p2.body2[0].y>(f.foody[0] - movesize - 1) && p2.body2[0].y < (f.foody[0] + movesize + 1))
{
p2.snakesize++;
f.number--;
f.flag[0] = 0;
}
if (f.flag[1] == 1 && p2.body2[0].x > (f.foodx[1] - movesize - 1) && p2.body2[0].x<(f.foodx[1] + movesize + 1) && p2.body2[0].y>(f.foody[1] - movesize - 1) && p2.body2[0].y < (f.foody[1] + movesize + 1))
{
p2.snakesize++;
f.number--;
f.flag[1] = 0;
}
if (f.flag[2] == 1 && p2.body2[0].x > (f.foodx[2] - movesize - 1) && p2.body2[0].x<(f.foodx[2] + movesize + 1) && p2.body2[0].y>(f.foody[2] - movesize - 1) && p2.body2[0].y < (f.foody[2] + movesize + 1))
{
p2.snakesize++;
f.number--;
f.flag[2] = 0;
}
*/
/*
//三个食物被吃了
if (f.flag[0] == 0)
{
f.foodx[0] = rand() % 1091;
f.foody[0] = rand() % 613;
f.flag[0] = 1;
}
if (f.flag[1] == 0)
{
f.foodx[1] = rand() % 1091;
f.foody[1] = rand() % 613;
f.flag[1] = 1;
}
if (f.flag[2] == 0)
{
f.foodx[2] = rand() % 1091;
f.foody[2] = rand() % 613;
f.flag[2] = 1;
}//
*/
/*
//画出食物
if (f.flag[0] == 1)
{
fillrectangle(f.foodx[0], f.foody[0], f.foodx[0] + movesize, f.foody[0] + movesize);
}
if (f.flag[1] == 1)
{
fillrectangle(f.foodx[1], f.foody[1], f.foodx[1] + movesize, f.foody[1] + movesize);
}
if (f.flag[2] == 1)
{
fillrectangle(f.foodx[2], f.foody[2], f.foodx[2] + movesize, f.foody[2] + movesize);
}*/
}
void drawgame()
{
BeginBatchDraw();
setbkcolor(GREEN);
cleardevice();
rectangle(0, 0, 1091, 613);//边框
setlinecolor(RED);
for (int i = 0;i < p1.snakesize;i++)
{
rectangle(p1.body1[i].x,p1.body1[i].y, p1.body1[i].x + movesize,p1.body1[i].y + movesize);
}
for (int i = 0;i < p2.snakesize;i++)
{
rectangle(p2.body2[i].x, p2.body2[i].y, p2.body2[i].x + movesize, p2.body2[i].y + movesize);
}
//food
eatfood();
//攻击
EndBatchDraw();
}
void key()
{
if (_kbhit())
{
switch (_getch())
{
case ' ':
while (1)
{
if (_getch() == ' ')
return;
}
break;
case 87:
if (p1.diret != down) {
p1.diret = up;
p1.body1[0].y -= p1.speed;
}
break;
case 83:
if (p1.diret != up) {
p1.diret = down;
p1.body1[0].y += p1.speed;
}
break;
case 65:
if (p1.diret != right) {
p1.diret = left;
p1.body1[0].x -= p1.speed;
}
break;
case 68:
if (p1.diret != left) {
p1.diret = right;
p1.body1[0].x += p1.speed;
}
break;
case 'i':
case 72://百度查的是上
if (p2.diret != down) {
p2.diret = up;
p2.body2[0].y -= p2.speed;
std::cout << "hello \n\n\n" << std::endl;
}
break;
case 'k':
case 80://百度查的是下
if (p2.diret != up) {
p2.diret = down;
p2.body2[0].y += p2.speed;
}
break;
case 'j':
case 75://左
if (p2.diret != right) {
p2.diret = left;
p2.body2[0].x -= p2.speed;
}
break;
case 'l':
case 77://右
if (p2.diret != left) {
p2.diret = right;
p2.body2[0].x += p2.speed;
}
break;
case '0':
gamemenu();
break;
}
}
}
void movesnake()
{
for (int i =p1.snakesize-1;i >0;i--)
{
p1.body1[i].x = p1.body1[i-1].x;
p1.body1[i].y = p1.body1[i-1].y;
}
for (int i = p2.snakesize - 1;i > 0;i--)
{
p2.body2[i].x = p2.body2[i - 1].x;
p2.body2[i].y = p2.body2[i - 1].y;
}
switch (p1.diret)
{
case up:
p1.body1[0].y-=movesize;
break;
case down:
p1.body1[0].y+=movesize;
break;
case left:
p1.body1[0].x-=movesize;
break;
case right:
p1.body1[0].x+=movesize;
break;
}
switch (p2.diret)
{
case up:
p2.body2[0].y -= movesize;
break;
case down:
p2.body2[0].y += movesize;
break;
case left:
p2.body2[0].x -= movesize;
break;
case right:
p2.body2[0].x += movesize;
break;
}
}
void gameover()
{
setbkcolor(BLUE);
cleardevice();
settextstyle(160, 0, _T("楷体"));
outtextxy(350, 200, _T("失败!"));
button(450, 375, 150, 50, "返回菜单");
ExMessage msg;
while (1)
{
while (peekmessage(&msg))
{
switch (msg.message)
{
case WM_LBUTTONDOWN:
if (msg.x > 449 && msg.x < 601 && msg.y>374 && msg.y < 426)
{
std::cout << "over " << std::endl;
gamemenu();
}
break;
}
}
}
}
int timer(int duration, int id)//替代sleep函数
{
static int starttime[10];
int endtime = clock();//返回当前程序运行时间(毫秒)
if (endtime - starttime[id] > duration)
{
starttime[id] = endtime;
return 1;
}
return 0;
}
void button(int x, int y, int w, int h, const char* text)//按钮绘制
{
setbkmode(TRANSPARENT);
setfillcolor(BROWN);
fillroundrect(x, y, x + w, y + h, 10, 10);
settextstyle(30, 0, "黑体");
//报错 重载函数 在属性里面使用多字符节
char text_[50] = "button";
strcpy_s(text_, text);
int tx = x + (w - textwidth(text)) / 2;
int ty = y + (h - textheight(text)) / 2;
outtextxy(tx, ty, text);
}
void gamemenu()
{
initgame();//
setbkcolor(BLUE);
cleardevice();
settextcolor(GREEN);
settextstyle(160, 0, _T("楷体"));
outtextxy(400, 100, _T("菜单"));
button(480,300,150, 50, "经典模式");
button(480, 375, 150, 50, "双人友好");
button(480, 450, 150, 50, "双人战斗");
button(480, 525, 150, 50, "自定义地图");
settextstyle(100, 0, _T("宋体"));
settextcolor(RED);
button(550,270,20,20,"?");
//fillrectangle(550,270,570,290);
ExMessage msg;
while (1)
{
while (peekmessage(&msg))
{
switch (msg.message)
{
//左键画圆 右键画圈
case WM_LBUTTONDOWN://左键按下
if (msg.x > 479 && msg.x < 631 && msg.y>374 && msg.y < 426)
{
twoplayergame();
}
if (msg.x > 479 && msg.x < 631 && msg.y>299 && msg.y < 351)
{
std::cout << "B" << std::endl;
singleplayergame();
}
if (msg.x > 549 && msg.x < 571 && msg.y>269 && msg.y < 291)
{
std::cout << "help \n" << std::endl;
drawhelp();
}
if (msg.x > 479 && msg.x < 631 && msg.y>449 && msg.y < 501)
{
battlemode();
}
break;
case WM_RBUTTONDOWN://右键按下
rectangle(msg.x - 5, msg.y - 5, msg.x + 5, msg.y + 5);
break;
}
}
}
}
void twoplayergame()
{
srand((unsigned int)time(0));//设置随机数种子
f.number = 3;
for (int i = 0; i < f.number; i++)
{
f.foodx[i] = 0;
f.foody[i] = 0;
f.flag[i] = 0;
}
while (1)
{
drawgame();
if (timer(30, 0))
movesnake();
if (p1.body1[0].x < 1 || p1.body1[0].x + movesize>1095 || p1.body1[0].y < 1 || p1.body1[0].y + movesize>613) { gameover(); }
if (p2.body2[0].x < 1 || p2.body2[0].x + movesize>1095 || p2.body2[0].y < 1 || p2.body2[0].y + movesize>613){ gameover(); }
//gameover();
key();
}
}
void singleplayergame()
{
srand((unsigned int)time(0));//设置随机数种子
food f1;
f1.flag[0] = 0;
f1.foodx[0] = 0;
f1.foody[0] = 0;
//int food = 0;
//int foodx = 0;
//int foody = 0;
while (1)
{
//FOOD
//if (f1.flag[0] == 1 && p1.body1[0].x > (f1.foodx[0] - movesize - 1) && p1.body1[0].x<(f1.foodx[0] + 1) && p1.body1[0].y>(f1.foody[0] - 1) && p1.body1[0].y < (f1.foody[0] + movesize + 1))
std::cout <<"x= "<< p1.body1[0].x << " " <<"y= "<< p1.body1[0].y << std::endl;
std::cout << "f1 flag=" << f1.flag[0] << " foodx= " << f1.foodx[0] << " foody= " << f1.foody[0] << std::endl;
if(f1.flag[0] == 1 && p1.body1[0].x > (f1.foodx[0] - movesize - 1) && p1.body1[0].x<(f1.foodx[0]+movesize + 1) && p1.body1[0].y>(f1.foody[0] -movesize- 1) && p1.body1[0].y < (f1.foody[0] +movesize+ 1))
{
p1.snakesize++;
f1.flag[0] = 0;
}
//setfillcolor(BLACK);
if (f1.flag[0] == 0)
{
f1.foodx[0] = rand() % 1091;
f1.foody[0] = rand() % 613;
//std::cout << "food draw" << foodx << foody << std::endl;
f1.flag[0] = 1;
}
//游戏绘制
BeginBatchDraw();
setbkcolor(GREEN);
cleardevice();
rectangle(0, 0, 1091, 613);//边框
setlinecolor(RED);
for (int i = 0; i < p1.snakesize; i++)
{
rectangle(p1.body1[i].x, p1.body1[i].y, p1.body1[i].x + movesize, p1.body1[i].y + movesize);
}
std::cout<<"size " << p1.snakesize << std::endl;
if (f1.flag[0] == 1)
{
fillrectangle(f1.foodx[0], f1.foody[0], f1.foodx[0] + movesize, f1.foody[0] + movesize);
}
EndBatchDraw();
//游戏移动
if (timer(250, 0))//250 0
{
for (int i = p1.snakesize - 1; i > 0; i--)
{
p1.body1[i].x = p1.body1[i - 1].x;
p1.body1[i].y = p1.body1[i - 1].y;
}
switch (p1.diret)
{
case up:
p1.body1[0].y -= movesize;
break;
case down:
p1.body1[0].y += movesize;
break;
case left:
p1.body1[0].x -= movesize;
break;
case right:
p1.body1[0].x += movesize;
break;
}
}
//游戏结束
if (p1.body1[0].x < 1 || p1.body1[0].x + movesize>1095 || p1.body1[0].y < 1 || p1.body1[0].y + movesize>613)
{
setbkcolor(BLUE);
cleardevice();
settextstyle(160, 0, _T("楷体"));
outtextxy(350, 200, _T("失败!"));
button(450, 375, 150, 50, "返回菜单");
ExMessage msg;
while (1)
{
while (peekmessage(&msg))
{
switch (msg.message)
{
case WM_LBUTTONDOWN:
if (msg.x > 449 && msg.x < 601 && msg.y>374 && msg.y < 426)
{
std::cout << "over " << std::endl;
gamemenu();
}
break;
}
}
}
}
//按键判断
if (_kbhit())
{
switch (_getch())
{
case ' ':
while (1)
{
if (_getch() == ' ')
std::cout << "here" << std::endl;
break;
}
break;
case 87:
if (p1.diret != down) {
p1.diret = up;
p1.body1[0].y -= p1.speed;
}
break;
case 83:
if (p1.diret != up) {
p1.diret = down;
p1.body1[0].y += p1.speed;
}
break;
case 65:
if (p1.diret != right) {
p1.diret = left;
p1.body1[0].x -= p1.speed;
}
break;
case 68:
if (p1.diret != left) {
p1.diret = right;
p1.body1[0].x += p1.speed;
}
break;
case '0':
gamemenu();
break;
}
}
}
}
void drawhelp()
{
setbkcolor(BLACK);
cleardevice();
settextcolor(WHITE);
settextstyle(32, 0, _T("宋体"));
outtextxy(10, 10, _T("经典模式"));
outtextxy(10, 90, _T("双人模式"));
outtextxy(10,170,_T("战斗模式"));
settextstyle(16, 0, _T("宋体"));
outtextxy(15, 60, _T("要开大写锁定,用WASD控制方向,非常经典"));//经典模式
outtextxy(15, 140, _T("也要开大写锁定WASD 和↑↓←→控制方向 只有触碰边缘才会结束游戏 速度较快"));//双人模式
outtextxy(15, 220, _T(""));//双人模式
settextcolor(WHITE);
button(10,550,80, 30, "返回");
ExMessage msg;
while (1)
{
while (peekmessage(&msg))
{
switch (msg.message)
{
case WM_LBUTTONDOWN:
if (msg.x > 9 && msg.x < 91 && msg.y>549 && msg.y < 581)
{
gamemenu();
}
break;
}
}
}
}
//攻击模式
void chooisespeed(int& a)
{
setbkcolor(BLUE);
cleardevice();
settextcolor(WHITE);
outtextxy(10, 40, _T("请选择速度:(250是单人模式下的速度,30是双人模式下的速度)"));
outtextxy(10, 80, _T("这个速度可以理解为绘制时间,绘制时间越小,绘制的越快自然跑的也越快"));
}
int attactfunction(int x,int y,int diret)
{
//画一个移动的小方格
BeginBatchDraw();
setlinecolor(RED);
rectangle(x, y, x + movesize, y + movesize);
EndBatchDraw();
//移动
switch (diret)
{
case up:
y -= movesize;
break;
case down:
y += movesize;
break;
case left:
x -= movesize;
break;
case right:
x += movesize;
break;
}
//销毁
if (x < 1 || x + movesize>1095 || y < 1 || y + movesize>613)
{
return 0;
}
}
void battlemode()
{//所有函数都写进这里面
//单独
//逻辑???
//选择速度
//选择snake 选择了一个要运行对应的attact生成函数
//
//
int a;
chooisespeed(a);
}
int main()
{
initgraph(1092, 614, EX_SHOWCONSOLE);
gamemenu();
//小技巧alt+鼠标左键垂直编辑
// std::cin.get();
}