目录
VS2022 EasyX库 C++
写在前面:贪吃蛇用数组模拟循环队列,最大长度(也即数组的长度)是里面宏定义的SNAKELENGTH,没有写判断最后是否满屏胜利。我自己加了一些选项界面虽然不太美观但也能看。蛇的移动是通过用背景(我的背景是白色的,所以我就用了一张白色的图片)覆盖最后一个节点,然后打印新的头部节点,这样子每次只需要对两个节点进行操作,不需要把所有的节点全部删除然后再打印。一开始写的时候用了链表,使用上出了点问题还有很高的延迟,所以直接换了方法。其中改变蛇颜色里的 loadimage 可以选择不同的节点样式(我自己画了几个。。),需要根据自己的图片文件位置进行更改,学过一些easyx的同学应该很容易操作。
开始界面
进入游戏后会看到如图的界面,START即开始游戏,所有选项都会按照默认设置。
- 地图大小:400*400
- 地图规则:不可穿墙
- 蛇身颜色:黑色
- 蛇行进速度:speed1(即 1/1 s前进一格)
OPTIONS界面
- RULE:进入更改游戏规则界面,即是否可以穿墙
- COLOUR:进入更改蛇身颜色界面
- SPEED:进入更改蛇速度界面
- MAPSIZE:进入更改地图大小界面
- BACK:返回上一界面
RULE界面
即是否可以穿墙
COLOUR界面
可选择的节点样式,可以根据自己的需求增加或删除
SPEED界面
分别对应 1/1 s ,1/2 s ,1/4 s , 1/8 s
MAPSIZE界面
更改地图大小,返回后应用(单位像素),默认为最小400*400
游戏界面
源码
#include <iostream>
#include <graphics.h>
#include <conio.h>
#include <time.h>
#define SNAKELENGTH 160
class MAP {
private:
int size; //大中小三种地图(20的倍数)800*800 、400*400 、 600*600 (再+20为一个节点的大小)
bool rule; //0 不能穿地图,1 可以
public:
MAP() :size(420), rule(false) {}
MAP(int a, bool b) :size(a), rule(b) {}
int get_size() {return size;}
bool get_rule() {return rule;}
void set_size(int sz) {size = sz;}
void set_rule(bool ru) {rule = ru;}
};
struct NODE {
int x, y;
};
struct SNAKE {
int length;
NODE body[SNAKELENGTH];
int head, tail;
int speed;
SNAKE(int len=0,int h=0,int t=0,int spd=1):length(len),head(h),tail(t),speed(spd) {
body[0].x = 200;
body[0].y = 200;
}
};
void START() { //绘制开始窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(180, 180, _T("START"));
outtextxy(180, 220, _T("OPTIONS"));
outtextxy(180, 260, _T("EXIT"));
}
void OPTIONS() { //绘制选项窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(180, 140, _T("RULE"));
outtextxy(180, 180, _T("COLOUR"));
outtextxy(180, 220, _T("SPEED"));
outtextxy(180, 260, _T("MAPSIZE"));
outtextxy(180, 300, _T("BACK"));
}
void RULE() { //绘制RULE窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(180, 180, _T("YES"));
outtextxy(180, 220, _T("NO"));
outtextxy(180, 260, _T("BACK"));
}
void COLOR() { //绘制调节蛇颜色窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(180, 180, _T("black"));
outtextxy(180, 220, _T("red"));
outtextxy(180, 260, _T("pink"));
outtextxy(180, 300, _T("green"));
outtextxy(180, 340, _T("BACK"));
}
void SPEED() { //绘制调节速度窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(180, 180, _T("speed1"));
outtextxy(180, 220, _T("speed2"));
outtextxy(180, 260, _T("speed4"));
outtextxy(180, 300, _T("speed8"));
outtextxy(180, 340, _T("BACK"));
}
void MAPSIZE() { //绘制调节地图大小窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(180, 180, _T("400*400"));
outtextxy(180, 220, _T("600*600"));
outtextxy(180, 260, _T("800*800"));
outtextxy(180, 300, _T("BACK"));
}
void EXIT() { //绘制退出窗口
setbkcolor(WHITE);
cleardevice();
setbkcolor(COLORREF(0x9c9690));
//绘制文本
settextcolor(BLACK);
settextstyle(20, 15, _T("黑体"));
outtextxy(50, 180, _T("DO IT YOURSELF"));
Sleep(1000000);
setbkcolor(WHITE);
cleardevice();
settextstyle(20, 0, _T("黑体"));
outtextxy(100, 200, _T("还是要我来"));
//Sleep(1000000);
}
int main() {
MAP my_map;
SNAKE my_snake(1, 0, 0, 1);
IMAGE my_style, white, food;
ExMessage mess;
int my_face=0;
int food_x, food_y;
loadimage(&my_style, _T("pho\\black.png"));
loadimage(&white, _T("pho\\white.png"));
loadimage(&food, _T("pho\\food.png"));
initgraph(420, 420);
START();
int start_x = 140, start_y = 180;
outtextxy(start_x, start_y, _T("->"));
while (1) { //接收开始游戏或结束游戏
char start_com = _getch();
if (start_com == 72 || start_com == 75) {
start_y -= 40;
if (start_y < 180) start_y = 260;
}
else if (start_com == 80 || start_com == 77) {
start_y += 40;
if (start_y > 260) start_y = 180;
}
else if (start_com == 13) {
if (start_y == 220) { //进入OPTIONS
OPTIONS();
int options_x = 140, options_y = 100;
while (1) { //接收options,选择设置
char options_com = _getch();
if (options_com == 72 || options_com == 75) {
options_y -= 40;
if (options_y < 140) options_y = 300;
}
else if (options_com == 80 || options_com == 77) {
options_y += 40;
if (options_y > 300) options_y = 140;
}
else if (options_com == 13) {
if (options_y == 140) { //改变规则
RULE();
int rule_x = 140, rule_y = 180;
outtextxy(rule_x, rule_y, _T("->"));
while (1) {
char rule_com = _getch();
if (rule_com == 72 || rule_com == 75) {
rule_y -= 40;
if (rule_y < 180) rule_y = 260;
}
else if (rule_com == 80 || rule_com == 77) {
rule_y += 40;
if (rule_y > 260) rule_y = 180;
}
else if (rule_com == 13) {
if (rule_y == 180) {
my_map.set_rule(1);
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
RULE();
outtextxy(rule_x, rule_y, _T("->"));
}
else if (rule_y == 220) {
my_map.set_rule(0);
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
RULE();
outtextxy(rule_x, rule_y, _T("->"));
}
else if (rule_y == 260) {
break;
}
}
RULE();
outtextxy(rule_x, rule_y, _T("->"));
}
}
else if (options_y == 180) { //改变蛇颜色
COLOR();
int color_x = 140, color_y = 180;
outtextxy(color_x, color_y, _T("->"));
while (1) {
char color_com = _getch();
if (color_com == 72 || color_com == 75) {
color_y -= 40;
if (color_y < 180) color_y = 340;
}
else if (color_com == 80 || color_com == 77) {
color_y += 40;
if (color_y > 340) color_y = 180;
}
else if (color_com == 13) {
if (color_y == 180) {
loadimage(&my_style, _T("pho\\black.png"));
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
COLOR();
outtextxy(color_x, color_y, _T("->"));
}
else if (color_y == 220) {
loadimage(&my_style, _T("pho\\red.png"));
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
COLOR();
outtextxy(color_x, color_y, _T("->"));
}
else if (color_y == 260) {
loadimage(&my_style, _T("pho\\pink.png"));
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
COLOR();
outtextxy(color_x, color_y, _T("->"));
}
else if (color_y == 300) {
loadimage(&my_style, _T("pho\\green.png"));
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
COLOR();
outtextxy(color_x, color_y, _T("->"));
}
else break;
}
COLOR();
outtextxy(color_x, color_y, _T("->"));
}
}
else if (options_y == 220) { //改变蛇速度
SPEED();
int speed_x = 140, speed_y = 180;
outtextxy(speed_x, speed_y, _T("->"));
while (1) {
char speed_com = _getch();
if (speed_com == 72 || speed_com == 75) {
speed_y -= 40;
if (speed_y < 180) speed_y = 340;
}
else if (speed_com == 80 || speed_com == 77) {
speed_y += 40;
if (speed_y > 340) speed_y = 180;
}
else if(speed_com==13) {
if (speed_y == 180) {
my_snake.speed = 1;
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
SPEED();
outtextxy(speed_x, speed_y, _T("->"));
}
else if (speed_y == 220) {
my_snake.speed = 2;
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
SPEED();
outtextxy(speed_x, speed_y, _T("->"));
}
else if (speed_y == 260) {
my_snake.speed = 4;
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
SPEED();
outtextxy(speed_x, speed_y, _T("->"));
}
else if (speed_y == 300) {
my_snake.speed = 8;
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
SPEED();
outtextxy(speed_x, speed_y, _T("->"));
}
else break;
}
SPEED();
outtextxy(speed_x, speed_y, _T("->"));
}
}
else if (options_y == 260) { //改变地图大小
MAPSIZE();
int map_x = 140, map_y = 180;
outtextxy(map_x, map_y, _T("->"));
while (1) {
char map_com = _getch();
if (map_com == 72 || map_com == 75) {
map_y -= 40;
if (map_y < 180) map_y = 300;
}
else if (map_com == 80 || map_com == 77) {
map_y += 40;
if (map_y > 300) map_y = 180;
}
else if (map_com == 13) {
if (map_y == 180) {
my_map.set_size(420);
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
MAPSIZE();
outtextxy(map_x, map_y, _T("->"));
}
else if (map_y == 220) {
my_map.set_size(620);
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
MAPSIZE();
outtextxy(map_x, map_y, _T("->"));
}
else if (map_y == 260) {
my_map.set_size(820);
outtextxy(0, 0, _T("SUCCEED!"));
Sleep(500);
MAPSIZE();
outtextxy(map_x, map_y, _T("->"));
}
else {
closegraph();
initgraph(my_map.get_size(), my_map.get_size());
MAPSIZE();
break;
}
}
MAPSIZE();
outtextxy(map_x, map_y, _T("->"));
}
}
else if (options_y == 300) { //返回上一菜单
break;
}
}
OPTIONS();
outtextxy(options_x, options_y, _T("->"));
}
}
else if (start_y == 260) { //进入EXIT
EXIT();
}
else { //进入STARTgame
int wait_time = 1000 / my_snake.speed;
int flag = 0; // 0 alive, 1 body_death, 2 wall_death
//初始化蛇的长度,头,尾,否则死过一次之后再也不能重新开始
my_snake.length = 1;
my_snake.head = 0;
my_snake.tail = 0;
setbkcolor(WHITE);
cleardevice();
srand(time(NULL));
food_x = rand() % (my_map.get_size() / 20 - 1) * 20;
food_y = (rand() - 654) % (my_map.get_size() / 20 - 1) * 20;
putimage(food_x, food_y, &food);
while (1) {
//接收移动指令
if (peekmessage(&mess, EM_KEY)) {
flushmessage();
if (mess.vkcode == VK_UP && my_face != 1) my_face = 0;
else if (mess.vkcode == VK_DOWN && my_face != 0) my_face = 1;
else if (mess.vkcode == VK_LEFT && my_face != 3) my_face = 2;
else if (mess.vkcode == VK_RIGHT && my_face != 2) my_face = 3;
}
//如果头部经过食物就重新生成食物坐标,同时保留最后一节作为加长的部分
if (my_snake.body[my_snake.head].x == food_x && my_snake.body[my_snake.head].y == food_y) {
int flag=1;//记录食物坐标是否与身体重合,1 重合,0 不重合
while (flag) {
flag = 0;
food_x = rand() % (my_map.get_size() / 20 - 1) * 20;
food_y = (rand() - 654) % (my_map.get_size() / 20 - 1) * 20;
for (int i = 0; i < my_snake.length; i++) { //判断食物坐标是否与身体重合,如果重合flag=1
int temp = (my_snake.tail + i) % SNAKELENGTH;
if (my_snake.body[temp].x == food_x && my_snake.body[temp].y == food_y) {
flag = 1;
}
}
}
putimage(food_x, food_y, &food);
my_snake.length++; //记录蛇的长度
}
else {
putimage(my_snake.body[my_snake.tail].x, my_snake.body[my_snake.tail].y, &white);//清除最后一节
my_snake.tail = (my_snake.tail + 1) % SNAKELENGTH; //确定新的尾部
}
my_snake.head = (my_snake.head + 1) % SNAKELENGTH; //确定新的头部
my_snake.body[my_snake.head].y = my_snake.body[(my_snake.head + SNAKELENGTH - 1) % SNAKELENGTH].y;
my_snake.body[my_snake.head].x = my_snake.body[(my_snake.head + SNAKELENGTH - 1) % SNAKELENGTH].x;
switch (my_face) { //新的头部坐标
case 0:my_snake.body[my_snake.head].y -= 20; break;
case 1:my_snake.body[my_snake.head].y += 20; break;
case 2:my_snake.body[my_snake.head].x -= 20; break;
case 3:my_snake.body[my_snake.head].x += 20; break;
}
//根据地图规则判断是否可以穿过地图边缘 (在打印新的头部之前,一定!!!!)
if (my_map.get_rule()) {
my_snake.body[my_snake.head].x = (my_snake.body[my_snake.head].x + my_map.get_size() ) % (my_map.get_size() );
my_snake.body[my_snake.head].y = (my_snake.body[my_snake.head].y + my_map.get_size() ) % (my_map.get_size() );
}
putimage(my_snake.body[my_snake.head].x, my_snake.body[my_snake.head].y, &my_style); //在新的头部地址打印身体
for (int i = 0; i < my_snake.length - 1; i++) { //判断死亡
int temp = my_snake.tail;
temp = (temp + i) % SNAKELENGTH;
//撞上自己的身体
if (my_snake.body[temp].x == my_snake.body[my_snake.head].x && my_snake.body[temp].y == my_snake.body[my_snake.head].y) {
flag = 1;
}
}
if (my_snake.body[my_snake.head].x<0 || my_snake.body[my_snake.head].x>my_map.get_size()-20 || my_snake.body[my_snake.head].y<0 || my_snake.body[my_snake.head].y>my_map.get_size()-20) {
flag = 2;
}
if (flag) {
if (flag == 1) outtextxy(my_map.get_size() / 2 - 150, my_map.get_size() / 2, _T("BODY DEATH!"));
else outtextxy(my_map.get_size() / 2 - 150, my_map.get_size() / 2, _T("WALL DEATH!"));
flag = 0;
Sleep(3000);
break;
}
Sleep(wait_time);
}
}
}
START();
outtextxy(start_x, start_y, _T("->"));
}
}