一、题目
贪吃蛇游戏机制是通过控制蛇上下左右移动并吃到食物得分。
蛇头碰到墙壁或者碰到蛇身就游戏结束。
食物随机生成,蛇吃到食物之后蛇身变长,蛇速加快。
二、算法
-
初始化游戏地图并打印,地图的边缘是墙,地图的每个坐标都有属性(EMPTY、WALL、FOOD、HEAD、BODY),通过<Window.h>库里面的函数控制光标跳转和颜色。
-
初始化蛇,蛇是一个单独的类,类里面的属性有蛇头、蛇身、长度、速度,蛇头一个SnakeNode节点,蛇身是一个SnakeNode指针,每个SnakeNode都是一个x、y坐标,用于表示蛇在地图上的位置。
-
随机生成食物,蛇移动的下一步如果是食物则得分,若下一步是墙壁或蛇身则游戏失败。
-
通过键盘输入控制方向,若键盘没有输入则保持方向不变。
三、代码
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning (disable:4996)
#include <iostream>
#include <Windows.h>
#include <conio.h>
#include <ctime>
#include <vector>
using namespace std;
#define ROW 22
#define COL 42
#define EMPTY 0
#define WALL 1
#define FOOD 2
#define HEAD 3
#define BODY 4
#define COL_WALL 6
#define COL_FOOD 12
#define COL_SNAKE 10
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define SPACE 32
#define ESC 27
#define ENTER 13
int g_map[ROW][COL] = { 0 };
int g_grade = 0;
void CursorJump(int x, int y)
{
COORD pos; //定义光标位置的结构体变量
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); //设置光标位置
}
void Color(int x)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x); //设置颜色
// 6------土黄色 7------白色 10------绿色 12------红色
}
void SysInit()
{
srand((unsigned int)time(NULL));
system("title 贪吃蛇");
system("mode con cols=84 lines=23"); //设置终端窗口大小
CONSOLE_CURSOR_INFO curInfo; //光标信息结构体变量
curInfo.dwSize = 1;
curInfo.bVisible = FALSE; //光标光标隐藏不可见
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &curInfo); //设置光标信息
}
void MapInit()
{
for (int i = 0; i < ROW; ++i)
{
for (int j = 0; j < COL; ++j)
{
CursorJump(2 * j, i);
if (i == 0 || i == ROW - 1 || j == 0 || j == COL - 1)
{
Color(COL_WALL);
g_map[i][j] = WALL;
cout << "■";
}
else
{
g_map[i][j] = EMPTY;
cout << " ";
}
}
}
Color(7);
CursorJump(0, ROW);
cout << "当前得分是:" << g_grade;
}
void RandFood()
{
int row, col;
do
{
row = rand() % ROW;
col = rand() % COL;
} while (g_map[row][col] != EMPTY);
g_map[row][col] = FOOD;
Color(COL_FOOD);
CursorJump(2 * col, row);
cout << "●";
}
class Snack
{
public:
Snack()
{
len = 2;
rate = 3000;
head.x = COL / 2;
head.y = ROW / 2;
g_map[head.y][head.x] = HEAD;
body.resize(ROW * COL, Pos(0, 0));
for (int i = 0; i < len; ++i)
{
body[i].x = head.x - i - 1;
body[i].y = head.y;
g_map[body[i].y][body[i].x] == BODY;
}
}
void PrintSnake(int flag)
{
if (flag)
{
// 打印蛇
Color(COL_SNAKE);
CursorJump(2 * head.x, head.y);
cout << "◆";
for (int i = 0; i < len; ++i)
{
CursorJump(2 * body[i].x, body[i].y);
cout << "◇";
}
}
else
{
// 覆盖蛇
if (body[len - 1].x != 0)
{
CursorJump(2 * body[len - 1].x, body[len - 1].y);
cout << " ";
}
}
}
void Judge(int x, int y)
{
if (g_map[head.y + y][head.x + x] == FOOD)
{
// 得分
g_grade += 10;
len++;
if (rate > 1000)
rate -= 50;
Color(7);
CursorJump(0, ROW);
cout << "当前得分是:" << g_grade;
RandFood();
}
else if (g_map[head.y + y][head.x + x] == WALL
|| g_map[head.y + y][head.x + x] == BODY)
{
// 失败
Sleep(2000);
Color(7);
system("cls");
cout << " GAME OVER! " << endl;
cout << " 游戏失败! " << endl;
exit(0);
}
}
void Move(int x, int y)
{
Judge(x, y);
PrintSnake(0);
int tail = len - 1;
g_map[body[tail].y][body[tail].x] = EMPTY;
while (tail > 0)
{
body[tail].x = body[tail - 1].x;
body[tail].y = body[tail - 1].y;
--tail;
}
body[0].x = head.x;
body[0].y = head.y;
g_map[body[0].y][body[0].x] = BODY;
head.x += x;
head.y += y;
g_map[head.y][head.x] = HEAD;
PrintSnake(1);
}
void Run(int x, int y)
{
int t = 0;
while (1)
{
if (t == 0)
t = rate;
while (--t)
{
if (kbhit() != 0)
break;
}
if (t == 0)
Move(x, y);
else
break;
}
}
void Play()
{
int dir = RIGHT;
int old = dir;
while (1)
{
switch (dir)
{
case 'w':
case 'W':
case UP:
Run(0, -1);
old = dir;
break;
case 's':
case 'S':
case DOWN:
Run(0, 1);
old = dir;
break;
case 'a':
case 'A':
case LEFT:
Run(-1, 0);
old = dir;
break;
case 'd':
case 'D':
case RIGHT:
Run(1, 0);
old = dir;
break;
case SPACE:
system("pause>nul");
break;
case ESC:
system("cls");
cout << " ESC 退出游戏" << endl;
exit(0);
}
dir = getch();
switch (dir)
{
case 'w':
case 'W':
case UP:
case 's':
case 'S':
case DOWN:
if (old == UP || old == DOWN)
dir = old;
break;
case 'a':
case 'A':
case LEFT:
case 'd':
case 'D':
case RIGHT:
if (old == LEFT || old == RIGHT)
dir = old;
break;
case SPACE:
case ESC:
break;
default:
dir = old;
}
}
}
private:
struct Pos
{
int x, y;
Pos() {}
Pos(int x1, int y1)
: x(x1), y(y1)
{}
};
Pos head;
vector<Pos> body;
int len;
int rate;
};
int main()
{
SysInit();
MapInit();
RandFood();
Snack s;
s.Play();
return 0;
}