写贪吃蛇的主要难点在于控制转向和自动移动,控制转向可以用switch语句控制,但要特别注意的是当蛇本身在向左走时右转向键是无效的,需要多些一个函数进行判断。
写自动移动的函数的时候只需要对蛇头和蛇尾两个点进行输出移动就可以的,其他的点只需改变坐标的值,而不用从新输出。
#include<windows.h>
#include<time.h>
#include<stdlib.h>
#include<conio.h>
#include<iostream>
#include<vector>
using namespace std;
#define N 24 //定义长和宽
int apple[2]; //标记苹果的坐标
static int grade=0;//记录成绩
class snake //记录蛇的坐标
{
public:
int x;
int y;
};
snake last; //标记蛇尾的坐标
vector<snake>snakes;//存放蛇的每一个点
void gotoxy(int x, int y)//改变位置的函数
{
COORD pos;
pos.X = 2 * x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void color(int a)//改变颜色的函数
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}
void inte_screen() //初始化并打印屏幕
{
int screen[N][N];
for (int i=0; i < N; ++i)
{
for (int j=0; j < N; ++j)
{
if (i == 0 || j == 0 || i==N-1 || j == N - 1)screen[i][j] = 0;
else screen[i][j] = 1;
}
}
color(11);
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
if (screen[i][j] == 0)cout << "□";
else cout << "■";
}
cout << endl;
}
}
void inte_snake() //初始化蛇
{
snake one;
color(14);
for (int i = 0; i < 3; ++i)
{
one.x = N / 2;
one.y = N / 2 - i;
snakes.push_back(one);
gotoxy(one.x, one.y);
cout << "★";
}
}
int* inte_apple() //随机产生苹果
{
while (1)
{
int f = 0;
srand((unsigned)time(NULL));
apple[0] = 1 + rand() % (N - 2);
apple[1] = 1 + rand() % (N - 2);
for (auto it = snakes.begin(); it != snakes.end(); ++it)//防止苹果出现在蛇上
if (apple[0] == it->x&&apple[1] == it->y)f = 1;
if (f == 0)
{
gotoxy(apple[0], apple[1]);
color(12);
cout << "●";
break;
}
}
return apple;
}
void move(char ch) //蛇移动
{
last.x = snakes.rbegin()->x; //蛇尾向前进一步
last.y = snakes.rbegin()->y;
gotoxy(snakes.rbegin()->x, snakes.rbegin()->y);
color(11);
cout << "■";
for (auto it1 = snakes.rbegin(); it1 != snakes.rend()-1; ++it1)//将蛇上的其他点向前进一
{
if ((it1 + 1)->x == it1->x)
{
if ((it1 + 1)->y > it1->y)it1->y++;
else it1->y--;
}
else
{
if ((it1 + 1)->x > it1->x)it1->x++;
else it1->x--;
}
}
auto it2 = snakes.begin(); //获取蛇头的位置并控制转向
color(14);
switch (ch)
{
case 'w':it2->y--; gotoxy(it2->x, it2->y); cout << "★"; break;
case 's':it2->y++; gotoxy(it2->x, it2->y); cout << "★"; break;
case 'a':it2->x--; gotoxy(it2->x, it2->y); cout << "★"; break;
case 'd':it2->x++; gotoxy(it2->x, it2->y); cout << "★"; break;
}
Sleep(400-5*grade);
}
bool judge_grade(int* apple) //判断蛇是否咬到苹果得分
{
if (snakes.begin()->x == apple[0] && snakes.begin()->y == apple[1])
{
grade++;
snakes.push_back(last);
gotoxy(last.x, last.y);
color(14);
cout << "★";
return true;
}
else return false;
}
void judge_swerve(char ch)//判断是否应该转向
{
auto it4 = snakes.begin();
switch (ch)
{
case 'w':
if ((it4 + 1)->x == it4->x && (it4 + 1)->y < it4->y)move('s');
else move('w');
break;
case 's':
if ((it4 + 1)->x == it4->x && (it4 + 1)->y > it4->y)move('w');
else move('s');
break;
case 'a':
if ((it4 + 1)->y == it4->y && (it4 + 1)->x < it4->x)move('d');
else move('a');
break;
case 'd':
if ((it4 + 1)->y == it4->y && (it4 + 1)->x > it4->x)move('a');
else move('d');
break;
}
}
bool judge_lose()//判断是否失败
{
if (snakes.begin()->x == 0 || snakes.begin()->y == 0 || snakes.begin()->x == N - 1 || snakes.begin()->y == N - 1)return true;
for (auto it5 = snakes.begin()+1; it5 != snakes.end(); ++it5)
{
if (snakes.begin()->x == it5->x&&snakes.begin()->y == it5->y)return true;
}
return false;
}
int main()
{
inte_screen();//初始化屏幕
inte_snake();//初始化蛇
gotoxy(N + 4, 1);
cout << "欢迎来到贪吃蛇";
gotoxy(N + 4, 2);
cout << "输入w,a,s,d移动";
char ch = 'p';//标记转向的字符
int f = 0;
while (1)
{
if (f == 0)//当上一个苹果被吃后再生成新的苹果
{
inte_apple();
f = 1;
}
if (_kbhit())//判断是否按下键
{
gotoxy(0, N + 2);
ch = _getche();
}
switch (ch) //进行转向
{
case 'w':judge_swerve(ch); break;
case 's':judge_swerve(ch); break;
case 'a':judge_swerve(ch); break;
case 'd':judge_swerve(ch); break;
default: break;
}
if (judge_grade(apple))//如果成功吃掉苹果将f置零从而产生新的苹果
{
f = 0;
}
gotoxy(N + 4, 3);
cout << "得分:" << " " << grade;
if (judge_lose())//判断是否失败,若失败打印GAMEOVER!!!
{
gotoxy(0, N + 4);
cout << "game over!!!";
break;
}
}
}