在学习了一点链表知识后,通过学习网上的贪吃蛇,花了一天多的时间,学习了整个思路流程后,用了一点自己的想法,然后写了个极其简易版的贪吃蛇,反正在写之前觉得麻烦,写了之后觉得要写字符简易版的话,不是太难。
在这里把思路记录下来:1.初始化。对各种信息初始化,比如蛇的结构,生命值,初始运动方向,产生食物等
2.游戏主体用一个while(life)的循环,当生命值为0时,游戏就结束
3.主体内:判断键入,根据键入值确定移动方向,WASD分别代表不同的值,利用switch()确定按得是哪一个键
4.判断移动后生命值是否等于0,依据是,根据移动了后蛇的头结点的位置来判断
5.画图。包括画边界,蛇,食物
6.返回循环
感觉写的有点混乱。大致意思就是这样。接下来尽量详细点写每个部分。
用到了几个主要的函数,如下:
void MakeFood(Snake * ptr)//这个函数用来产生食物
随机生成一个位置,和蛇身体比较,如果相同,则重新生成
void DrawMap(Snake * ptr)//画图,蛇,食物
要绘制的整个图用一个二维数组表示。用一个二维数组,先给边界赋值,画出边界,中间空白就用‘ ’这种空白表示。食物用food[]表示,x=food[0],y=food[1],这个是通过MakeFood函数产生的,再把它赋值给map[][]。蛇的位置是通过遍历链表来确定的。
struct Snake * UpdateSnake(Snake * ptr, int z)//更新蛇的坐标
根据移动方向,更新x,y。移动的方式是,添加一个头结点,也就是链表的插入操作,然后判断吃到食物没,吃到,则不删除末节点,没吃到,则删除,这个相当于链表的删除操作。最后返回链表头结点head。
int KeyDown(int z)//获取键值
利用 _getch()函数,和switch(),判断按下的是哪个键。
蛇的身体是用一个结构表示:
struct Snake
{
int x;
int y;
struct Snake * next;
}
基本就是这样了。
第二次用博客,不知道这样贴代码的方式正确不,(⊙o⊙)…,,,,里面有些功能还没完善,所以这个版本是极简易的,才学C++没多久,所以太菜,在继续学习后,以后可能会返回来修改完善
#include<iostream>
#include<ctime>
#include<conio.h> //包含kbhit()
#include<Windows.h>
typedef struct Snake * NodePtr;
void MakeFood(Snake * ptr);//产生食物
void DrawMap(Snake * ptr);//画地图,画蛇,画食物
void gotoxy(int x, int y);//光标定位到(x,y)
struct Snake * UpdateSnake(Snake * ptr, int z);//更新蛇的坐标,返回头结点
int KeyDown(int z);//获取键入
using namespace std;
int life = 1;//生命,如果等于0,则结束,等于1,则继续
const int WIDTH = 30;
char map[WIDTH][WIDTH];//把地图定义成数组
struct Snake//定义一个结构表示蛇的身体,用链表结构表示
{
int x;//每一节身体的坐标(x,y)
int y;
NodePtr next;//指针指向下一节身体
};
int speed = 100;
int food[2]; //food[0] = x, food[1] = y
int point = 0;//记录得分
/*----------------------主函数----------------------------------*/
int main()
{
system("title 贪吃蛇");
int z = 4;//设置初始移动方向 1=A,2=D,3=S,4=W
//system("mode con cols = 500 lines = 300");//控制台的宽度和高度,不知道为什么是无效的参数
NodePtr head;//初始化蛇的头结点
head = (NodePtr)malloc(sizeof(struct Snake));
head->x = 10;//第一个结点坐标(10,10)
head->y = 10;
head->next = (NodePtr)malloc(sizeof(struct Snake));//为第二个结点分配空间
head->next->x = 10;//初始化第二个结点坐标(10,9)
head->next->y = 9;
head->next->next = NULL;
gotoxy(2, 10);
cout << "W:上 S:下 A:左 D:右 Esc:结束游戏退出";
Sleep(2500);
MakeFood(head);
/*-----游戏主循环-----*/
while(1)
{
//DrawMap(head);
z = KeyDown(z);
if(z == 27)//按ESC退出
break;
head = UpdateSnake(head, z);
if(life == 0)
break;
DrawMap(head);
//drawmap(head);
Sleep(300 - speed);
}
gotoxy(30, 15);
cout << "Game over!";
Sleep(2500);
return 0;
}
/*----------------------产生食物------------------------------------*/
void MakeFood(Snake * ptr)
{
Snake * check = ptr;//利用check来遍历链表,将每个结点和产生的食物进行位置比较
srand((unsigned)clock());
food[0] = rand() % 25;
food[1] = rand() % 25;
do
{
if(food[0] == check->x && food[1] == check->y)
MakeFood(ptr);
check = check->next;
} while(check != NULL);
}
/*-----------------------画地图、蛇、食物-----------------------------------*/
void DrawMap(Snake * ptr)
{
system("cls");
//地图,地图大小30X30
for(int i = 0; i < 30; i++)
map[0][i] = '+';
for(int i = 1; i <= 28; i++)
{
for(int j = 0; j < 30;j++)
if(j == 0 || j == 29)
map[i][j] = '+';
else
map[i][j] = ' ';
}
for(int i = 0; i < 30; i++)
map[29][i] = '+';
//蛇
while(ptr)
{
map[ptr->x][ptr->y] = '#';
ptr = ptr->next;
}
//食物
map[food[0]][food[1]] = '*';
//打印地图
for(int i = 0; i < 30; i++)
{
for(int j = 0; j < 30; j++)
cout << map[i][j];
cout << endl;
}
}
/*-----------------------更新蛇的坐标-----------------------------------*/
struct Snake * UpdateSnake(Snake * ptr, int z)
{
NodePtr first, rear, check;
int x, y;//更新x,y
//int last = 2;//记录末节点的位置
x = ptr->x;
y = ptr->y;
switch(z)//这一段用来计算坐标的变化
{
case 1:y--; break;//这里的X,Y的坐标变化要注意,和平时的坐标系是反的
case 2:y++; break;
case 3:x--; break;
case 4:x++; break;
}
first = (NodePtr)malloc(sizeof(struct Snake));//插入头结点
first->x = x;
first->y = y;
first->next = ptr;
//检查头有没有碰到身体或者墙壁,碰到则life = 0,游戏结束
check = ptr;
while(check)
{
if( check->x == first->x && check->y == first->y )
life = 0;
else
check = check->next;
}
if(first->x >= 30 || first->x <= 0 || first->y >= 30 || first->y <= 0)
life = 0;
//检查有没有吃到食物,如果吃到,则不删除尾结点,否则删除末节点
if(first->x == food[0] && first->y == food[1])
{
point++;//如果吃到,则积分+1
//last = last + 1;//更新记录末节点的数据
MakeFood(first);//产生下一个新食物
//return first;//返回新的头结点
}
else//删除末节点
{
while(ptr->next->next != NULL)
ptr = ptr->next;
rear = ptr->next;
ptr->next = NULL;
free(rear);
//return first;
}
return first;
}
/*-----------------------获取键入--------------------------------*/
int KeyDown(int z)
{
char ch;
if(_kbhit())
{
ch = _getch();
switch(ch)//z=1 代表A,左移;z =2代表D,右移;z = 3,代表W,上移;z = 4,代表S,下移
{
case 'A':
case 'a':if(z != 2) z = 1; break;//如果没有右移的话,按下A就应该是左移
case 'D':
case 'd':if(z != 1) z = 2; break;
case 'W':
case 'w':if(z != 4) z = 3; break;
case 'S':
case 's':if(z != 3) z = 4; break;
default:break;
}
if(ch == 27)
z = 27;//ESC
}
return z;
}
/*-------------将光标移到指定位置---------------------*/
void gotoxy(int x, int y)
{
COORD pos = { x, y };//COORD是Windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, pos);
}