在长度已知的情况下,创建一个int型变量lenth来确定数组的上限比用链表查找到NULL要简单一些。
#include <iostream>
#include <cstring>
#include <Windows.h>
#include <conio.h>
#include <time.h>
using namespace std;
int score = 0; //初始分数与长度
int lenth = 3;
int food_line, food_colu; //食物所在的行列(没有写x,y,因为x和图上的行是反的,不便于理解)
typedef struct
{
int line; //line行,column为列,此处简写colu
int colu;
}Body;
Body snake[1000]; //蛇身上限为1000
void Gotoxy(int x, int y); //光标移动函数
void Color(int x); //颜色改变函数
void Gotoprint(int x, int y); //移动到指定坐标,然后打印■
void Gotodelete(int x, int y); //移动到指定坐标,然后打印" "(空格),实现删除
void Color_change(int scores); //打印分数的时候改变分数的颜色
void Welcome(); //欢迎界面
void Clean_welcome(); //清除欢迎界面
void Initialize(); //初始化函数
void Play(); //游戏运行函数
void Creat_fence(); //创造墙
void Creat_score(); //创造分数
bool Judge(); //判断游戏是否结束
void Move(); //身体移动
void Turn(char click); //身体转向
void Print_body(); //打印身体函数
void Wait(); //根据分数选择Sleep()的时间
void Creat_food(); //创造食物
bool Food_exist(); //判断食物是否被吃了
void Body_extend(); //身体变长函数
void End(); //结束界面
//打印■时,需要占据两个水平单位的大小,即■只能打印在偶数横坐标上,否则无法显示,因此蛇的身体的横坐标也必须为偶数
int main()
{
Welcome();
Initialize();
Creat_fence();
Play();
End();
}
void Gotoxy(int x, int y) //具体内容参考百度百科
{
COORD pos;
HANDLE hOutput;
pos.X = x;
pos.Y = y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, pos);
}
void Color(int x) //自定义函根据参数改变颜色
{
if (x >= 0 && x <= 15) //参数在0-15的范围颜色
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x); //只有一个参数,改变字体颜色
}
else //默认的颜色白色
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
}
void Gotoprint(int x, int y)
{
Gotoxy(x, y);
cout << "■";
}
void Gotodelete(int x, int y)
{
Gotoxy(x, y);
cout << " ";
Gotoxy(x + 1, y);
cout << " ";
}
void Color_change(int scores)
{
if (scores > 250)
{
Color(13);
}
else if (scores > 200)
{
Color(12);
}
else if (scores > 150)
{
Color(9);
}
else if (scores > 100)
{
Color(10);
}
else if (scores > 50)
{
Color(14);
}
else
{
Color(7);
}
}
void Welcome()
{
Gotoxy(15, 10); Color(7);
cout << "---------------------------------";
Gotoxy(15, 11); Color(11);
cout << "Welcome come to paly this game!";
Gotoxy(15, 12);
cout << "Press any key to continue";
Gotoxy(15, 13); Color(7);
cout << "---------------------------------";
Gotoxy(60, 12); Color(12);
cout << "Created by Morning";
_getch();
Clean_welcome();
}
void Clean_welcome()
{
Gotoxy(15, 10);
cout << " ";
Gotoxy(15, 11);
cout << " ";
Gotoxy(15, 12);
cout << " ";
Gotoxy(15, 13);
cout << " ";
Gotoxy(60, 12);
cout << " ";
}
void Initialize()
{
memset(snake, -1, sizeof(snake)); //身体部分的初始化
snake[0].line = 16;
snake[0].colu = 16;
snake[1].line = 16;
snake[1].colu = 17;
snake[2].line = 16;
snake[2].colu = 18;
Print_body();
Creat_food(); //食物的初始化
}
void Creat_fence()
{
Color(11);
int i = 0;
for (i = 0; i <= 50; i += 2) //打印上下边框
{
Gotoprint(i, 0);
Gotoprint(i, 25);
}
for (i = 1; i <= 25; ++i) //打印左右边框
{
Gotoprint(0, i);
Gotoprint(50, i);
}
Gotoxy(57, 11); Color(7);
cout << "----- Your Score is";
Gotoxy(81, 11);
cout << "-----";
Gotoxy(63, 13);
cout << "Press WASD to move";
Gotoxy(63, 14);
cout << " ";
Gotoxy(63, 14);
cout << "Press P to pause";
}
void Creat_score()
{
Gotoxy(78, 11); Color_change(score);
cout << score;
Color(11);
}
void Play()
{
while (Judge() == true)
{
Creat_fence();
Creat_score(); //创建分数
if (_kbhit()) //如果有键盘输入则转向,_kbhit为非阻塞函数,_getch为阻塞函数,区别详见百度
{
char click = _getch();
Turn(click);
}
else //没有输入则向前移动
{
Move(); //身体移动
}
if (Food_exist() == false)
{
Gotodelete(food_line, food_colu); //清除原先食物
Body_extend(); //身体长长
Creat_food(); //创建新食物
score += 10; //分数+10
}
}
}
bool Judge()
{
int re = true;
if (snake[0].colu <= 0 || snake[0].colu >= 25) //碰到上下墙
{
re = false;
}
else if (snake[0].line <= 0 || snake[0].line >= 50) //碰到左右墙
{
re = false;
}
else
{
for (int i = 1; i <= lenth - 1; ++i) //遍历自身,判断身体中是否有部位与头部相接
{
if (snake[i].colu == snake[0].colu && snake[i].line == snake[0].line) //吃到自己
{
re = false;
break;
}
}
}
return (re);
}
void Move()
{
for (int i = 0; i <= lenth - 1; ++i) //身体图像的清除,通过清除原先图像再打印新图像实现动画效果
{
Gotodelete(snake[i].line, snake[i].colu);
}
Body swap[1000];
for (int i = 0; i <= lenth - 1; ++i) //用另一个数组存放原来身体的数据
{
swap[i] = snake[i];
}
int line = snake[0].line - snake[1].line; //line用于判断头部和第二节的位置关系
int colu = snake[0].colu - snake[1].colu;
if (line < 0) //如果头在第二节的左边,则头部向左移动两个单位
{
snake[0].line -= 2; //移动头部,其余部分移至其前一节
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
}
else if (line > 0) //如果头在第二节右边,则头部向右移动两个单位
{
snake[0].line += 2;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
}
else if (colu < 0) //如果头在第二节上边(即上一行),则头部向上移动一个单位
{
snake[0].colu -= 1;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
}
else //如果头在第二节下边,则头部向下移动一个单位
{
snake[0].colu += 1;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
}
Print_body(); //打印新身体
Wait();
}
void Turn(char click)
{
for (int i = 0; i <= lenth - 1; ++i) //身体图像的清除
{
Gotodelete(snake[i].line, snake[i].colu);
}
Body swap[1000];
for (int i = 0; i <= lenth - 1; ++i) //用另一个数组存放原来身体的数据
{
swap[i] = snake[i];
}
int line = snake[0].line - snake[1].line;
int colu = snake[0].colu - snake[1].colu;
switch (click)
{
case 'A':
case 'a':
if (line < 0 || line>0) //左移或右移时,只能向上或向下转动
{
break;
}
else
{
snake[0].line -= 2;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
break;
}
case 'D':
case 'd':
if (line < 0 || line>0)
{
break;
}
else
{
snake[0].line += 2;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
break;
}
case 'W':
case 'w':
if (colu < 0 || colu>0) //上移或下移时,只能向左或向右转动
{
break;
}
else
{
snake[0].colu -= 1;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
break;
}
case 'S':
case 's':
if (colu < 0 || colu>0)
{
break;
}
else
{
snake[0].colu += 1;
for (int i = 0; i <= lenth - 2; ++i)
{
snake[i + 1] = swap[i];
}
break;
}
case 'P': //按p暂停
case 'p':
Gotoxy(63, 14); Color(7);
cout << "Press any key to continue";
Color(11);
Print_body();
_getch();
}
Print_body();
}
void Print_body()
{
for (int i = 0; i <= lenth - 1; ++i)
{
Gotoprint(snake[i].line, snake[i].colu);
}
}
void Wait()
{
if (score > 180)
{
Sleep(50);
}
else if (score > 150)
{
Sleep(100);
}
else if (score > 120)
{
Sleep(150);
}
else if (score > 90)
{
Sleep(200);
}
else if (score > 60)
{
Sleep(250);
}
else
{
Sleep(300);
}
}
void Creat_food()
{
A:
srand((int)time(NULL));
food_line = rand() % (48 - 1 + 1) + 1;
food_colu = rand() % (23 - 2 + 1) + 2;
if (food_line % 2 != 0) //一个■需要占两个水平方向单位长度,判断其是否在双数位上,若在单数位上则不显示
{
food_line++;
}
for (int i = 0; i <= lenth - 1; ++i) //判断食物是否在蛇身上
{
if (snake[i].colu == food_colu && snake[i].line == food_line)
{
goto A; //如果在蛇身上则重新生成(偷个懒,写了个goto)
}
}
Color(12); //打印前切换为红色,打印后切换回青色
Gotoxy(food_line, food_colu);
printf("⊙");
Color(11);
}
bool Food_exist()
{
int re;
if (snake[0].colu == food_colu && snake[0].line == food_line)
{
re = false;
}
else
{
re = true;
}
return (re);
}
void Body_extend()
{
int line = snake[lenth - 1].line - snake[lenth - 2].line;
int colu = snake[lenth - 1].colu - snake[lenth - 2].colu;
if (line < 0) //如果倒数第一节在倒数第二节的左边
{
snake[lenth].line = snake[lenth - 1].line - 2; //那么新的一节就在倒数第一节的左边一个单位
snake[lenth].colu = snake[lenth - 1].colu;
}
else if (line > 0)
{
snake[lenth].line = snake[lenth - 1].line + 2;
snake[lenth].colu = snake[lenth - 1].colu;
}
else if (colu < 0)
{
snake[lenth].line = snake[lenth - 1].line;
snake[lenth].colu = snake[lenth - 1].colu - 1;
}
else
{
snake[lenth].line = snake[lenth - 1].line;
snake[lenth].colu = snake[lenth - 1].colu + 1;
}
++lenth;
Print_body();
}
void End()
{
for (int i = 0; i <= lenth - 1; ++i) //清除蛇身
{
Gotodelete(snake[i].line, snake[i].colu);
}
int i = 0;
for (i = 0; i <= 50; i += 2) //清除上下边框
{
Gotodelete(i, 0);
Gotodelete(i, 25);
}
for (i = 1; i <= 25; ++i) //清除左右边框
{
Gotodelete(0, i);
Gotodelete(50, i);
}
Gotodelete(food_line, food_colu); //清除食物
Gotoxy(57, 11); Color(7); //清除分数表
cout << " ";
Gotoxy(81, 11);
cout << " ";
Gotoxy(63, 13);
cout << " ";
Gotoxy(63, 14);
cout << " ";
Gotoxy(15, 12); Color(11);
cout << "Congratulation!";
Gotoxy(15, 13);
cout << "Your score is ";
Color_change(score);
cout << score;
Gotoxy(15, 14); Color(11);
cout << "Press any key to end this game";
_getch(); //多用了几个getch防止暴躁老哥按急了最后看不到成绩
_getch();
_getch();
_getch();
_getch();
_getch();
_getch();
}