#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 是蛇占满了屏幕,会因为食物没有地方生成,会卡住)
游戏截图: