第一个简陋版贪吃蛇终于成功了

在学习了一点链表知识后,通过学习网上的贪吃蛇,花了一天多的时间,学习了整个思路流程后,用了一点自己的想法,然后写了个极其简易版的贪吃蛇,反正在写之前觉得麻烦,写了之后觉得要写字符简易版的话,不是太难。

在这里把思路记录下来: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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值