(EGE)无尽贪吃蛇

#include <ctime>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <graphics.h>

const int W = 20; //宽
const int H = 15; //高
const int L = 30; //块大小(这个不建议修改

int snake [W * H * 2] = {0};  //蛇
int snakeLength;      //蛇长,迟到食物会增加
int headX, headY;     //朝向,总有一个是 0,不然斜着走
int foodX, foodY;      //食物坐标(目前之设置了一个食物
int interval = 500;    //时间间隔,单位是 ms,可以用 Q,E 来调节间隔以便调节游戏速度

void drawBody (int x, int y) {
	// 这个 x,y 为像素,用于画蛇身
	setfillcolor (EGERGB (23, 187, 38));
	bar (x + 3, y + 3, x + 27, y + 27);
}
void drawFood (int x, int y) {
	// 这个 x,y 为像素,用于画食物
	setfillcolor (EGERGB (214, 214, 214));
	bar (x + 7, y + 7, x + 23, y + 23);
}

void init (void) {
// 初始化,也就是新开一局
	for (int i = 0; i < W*H*2-1; i += 1) { snake [i] = 0; }
	snake [0] = rand () % W;
	snake [1] = rand () % H;
	// 初始化 蛇 相关
	foodX = rand () % W;
	foodY = rand () % H;
	// 初始化食物位置
	headX = 0; headY = 0;
	switch (rand () % 4) {
		case 0: headX = -1; break;
		case 1: headX = 1;  break;
		case 2: headY = -1; break;
		case 3: headY = 1;  break;
	}
	// 初始化蛇头方向
	snakeLength = 1;
	// 初始化蛇长
}
void control (void) {
// 按键处理,移动和调节时间间隔
	if (keystate (VK_UP)) {
		headY = -1; headX = 0;
	} else if (keystate (VK_DOWN)) {
		headY = 1; headX = 0;
	} else if (keystate (VK_LEFT)) {
		headX = -1; headY = 0;
	} else if (keystate (VK_RIGHT)) {
		headX = 1; headY = 0;
	} else if (keystate (81)) {
		interval -= 10;
	} else if (keystate (69)) {
		interval += 10;
	}
}
void edgeCheck (void) {
// 边界处理,当蛇头到达墙边,此时可以穿墙而过,到达另一边
	if (snake [0] < 0) {
		snake [0] = W - 1;
	} else if (snake [0] > W - 1) {
		snake [0] = 0;
	} else if (snake [1] < 0) {
		snake [1] = H - 1;
	} else if (snake [1] > H - 1) {
		snake [1] = 0;
	}
}
bool foodCheck (int x, int y) {
// 检查食物生成位置不在蛇身上,是返回 true,否返回 false
	for (int i = 0; i < snakeLength; i += 1) {
		if (x == snake [2 * i] && y == snake [2 * i + 1]) {
			return true;
		}
	}
	return false;
}
// 其实这两个函数长的真的好像,但是上面那个检查了蛇头,下面不检查蛇头
bool bodyCheck (int x, int y) {
// 检查蛇头是否吃到自己,是返回 true,否返回 false
	for (int i = 2; i < snakeLength; i += 1) {
		if (x == snake [2 * i] && y == snake [2 * i + 1]) {
			return true;
		}
	}
	return false;
}
bool move (void) {
// 移动,用 headX,和 headY 决定蛇头往哪一个方向移动
	if (snake [0] + headX == foodX &&
	    snake [1] + headY == foodY) {
// 有没有吃到食物,吃到则增加蛇长,并重新生成食物
		snakeLength += 1;
re:		foodX = rand () % W;
		foodY = rand () % H;
		if (foodCheck (foodX, foodY)) {
		// 若食物生成在蛇身上,则重新生成(BUG 就在这里了,蛇身要是先占满屏幕就没有食物的位置了)
			goto re;
		}
	}
	for (int i = 2 * snakeLength - 1; i > 1; i -= 2) {
	// 移动蛇身,很客观世界的操作
		snake [i - 1] = snake [i - 3];
		snake [  i  ] = snake [i - 2];
	}
	snake [0] += headX;
	snake [1] += headY;
	// 移动蛇头
	edgeCheck ();
	// 边界检测
	if (bodyCheck (snake [0], snake [1])) {
	// 如果蛇吃到了自己,move 返回 ture,否则 返回 false
		return true;
	} else {
	        return false;
	}
}


void show (void) {
// 简单的把蛇身和食物的位置画出来
	drawFood (foodX * L, foodY * L);
	
	for (int i = 2 * snakeLength - 1; i > 1; i -= 2) {
		drawBody (snake [i - 1] * L, snake [i] * L);
		
		if (abs ( snake [i - 1] - snake [i - 3]) <= 1 &&
		    abs ( snake [  i  ] - snake [i - 2]) <= 1) {
		    // 填补两个蛇身之间的空隙,上面这个绝对值是解决蛇穿墙的问题
		    // 如果不检测蛇身之间的距离,会突然发现屏幕中间出现一个蛇身
			int x = ((snake [i - 1] + snake [i - 3]) * L) / 2;
			int y = ((snake [  i  ] + snake [i - 2]) * L)/ 2;
			drawBody (x, y);
		}
	}
	drawBody (snake [0] * L, snake [1] * L);
}

int main () {
	
	srand (time (0)+clock ());
  // 随机种子
	setinitmode (INIT_RENDERMANUAL);
	initgraph (L * W, L * H);

	init ();
	int lastTime = clock ();

	for (;is_run (); delay_fps (60), cleardevice ()) {
		control ();
		if (clock () - lastTime > interval) {
			if (move ()) { init (); }
			lastTime = clock ();
		}
		show ();
	}

	getch ();
	closegraph ();

	return 0;
}

Q:加快速度

E:减慢速度

方向键移动,暂不支持自定义快捷键,没有分数,吃到自己会重开一局

可以穿墙

(未来可能会增加障碍物和关卡)

(目前猜测 BUG 是蛇占满了屏幕,会因为食物没有地方生成,会卡住)

游戏截图:

深度截图_选择区域_20200303181400.png