C++STL13_贪吃蛇案例

01 贪食蛇玩法介绍以及编码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

02贪食蛇墙模块实现

代码结构:
在这里插入图片描述
wall.h:

#ifndef _WALL_HEAD
#define _WALL_HEAD
#include<iostream>
using namespace std;

class Wall
{
public:
	enum {
		ROW = 20,
		COL = 20
	};

	//初始化墙壁
	void initWall();

	//画出墙壁
	void drawWall();

	//根据索引设置,二维数组里的内容
	void setWall(int x, int y, char c);

	//根据索引获取当前位置的符号
	char getWall(int x, int y);

private:
	char gameArray[ROW][COL];
};
#endif // !_WALL_HEAD

wall.cpp:

#include"wall.h"

void Wall::initWall()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			//放墙壁
			if (i == 0 || j == 0 || i == ROW - 1 || j == COL - 1)
			{
				gameArray[i][j] = '*';
			}
			else
			{
				gameArray[i][j] = ' '; 
			}
		}
	}
}

void Wall::drawWall()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			cout << gameArray[i][j] << " ";
		}
		if (i == 5)
		{
			cout << "create by zt";
		}
		if (i == 6)
		{
			cout << "a:left";
		}
		if (i == 7)
		{
			cout << "b:right";
		}
		if (i == 8)
		{
			cout << "w:up";
		}
		if (i == 9)
		{
			cout << "s:down";
		}
		cout << endl;
	}
}

void Wall::setWall(int x, int y, char c)
{
	gameArray[x][y] = c;
}

char Wall::getWall(int x, int y)
{
	return gameArray[x][y];
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"

int main()
{
	Wall wall;
	wall.initWall();

	//测试
	wall.setWall(5, 4, '=');
	wall.setWall(5, 5, '=');
	wall.setWall(5, 6, '@');

	wall.drawWall();

	cout << wall.getWall(0, 0) << endl;
	cout << wall.getWall(5, 4) << endl;
	cout << wall.getWall(5, 6) << endl;
	cout << wall.getWall(1, 1) << endl;

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

03 贪食蛇案例-蛇模块

代码结构:
在这里插入图片描述
snake.h:

#pragma once
#include<iostream>
#include"wall.h"
using namespace std;

class Snake
{
public:
	Snake(Wall & tempWall);
	//节点
	struct  Point
	{
		//数据域
		int x;
		int y;

		//指针域
		Point* next;
	};

	void initSnake();

	//销毁节点
	void destroyPoint();

	//添加节点
	void addPoint(int x, int y);

	Point* pHead;

	Wall& wall;
};

snake.cpp:

#include "snake.h"

Snake::Snake(Wall& tempWall):wall(tempWall)
{
	pHead = NULL;
}

void Snake::initSnake()
{
	destroyPoint();
	addPoint(5, 3);
	addPoint(5, 4);
	addPoint(5, 5);
}

void Snake::destroyPoint()
{
	Point* pCur = pHead;
	while (pHead != NULL)
	{
		pCur = pHead->next;
		delete pHead;
		pHead = pCur;
	}
}

void Snake::addPoint(int x, int y)
{
	//创建新节点
	Point* newPoint = new Point;
	newPoint->x = x;
	newPoint->y = y;
	newPoint->next = NULL;

	//如果原来头不为空,改为 身子
	if (pHead != NULL)
	{
		wall.setWall(pHead->x, pHead->y, '=');
	}
	newPoint->next = pHead;
	pHead = newPoint;//更新头部
	wall.setWall(pHead->x, pHead -> y, '@');
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"
#include"snake.h"

int main()
{
	Wall wall;
	wall.initWall();

	Snake snake(wall);
	snake.initSnake();

	wall.drawWall();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

04 贪食蛇-食物模块

代码结构:
在这里插入图片描述
food.h:

#pragma once
#include<iostream>
using namespace std;
#include"wall.h"

class Food
{
public:
	Food(Wall& tempWall);
	//设置食物
	void setFood();

	int foodX;
	int foodY;

	Wall& wall;
};

food.cpp:

#include "food.h"

Food::Food(Wall& tempWall):wall(tempWall)
{
}

void Food::setFood()
{
	while (true)
	{
		foodX = rand() % (Wall::ROW - 2) + 1;
		foodY = rand() % (Wall::COL - 2) + 1;

		//如果随机的位置是蛇头或蛇身,就重新生成随机数
		if (wall.getWall(foodX, foodY) == ' ')
		{
			wall.setWall(foodX, foodY, '#');
			break;
		}
	}
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"
#include"snake.h"
#include"food.h"
#include<ctime>

int main()
{
	//添加随机种子
	srand((unsigned int)time(NULL));
	Wall wall;
	wall.initWall();

	Snake snake(wall);
	snake.initSnake();

	Food food(wall);
	food.setFood();

	wall.drawWall();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

05 删除尾节点和移动封装

snake.h:

#pragma once
#include<iostream>
#include"wall.h"
#include"food.h"
using namespace std;

class Snake
{
public:
	Snake(Wall & tempWall,Food & ftmpFood);

	enum{ UP = 'w',DOWN ='s',LEFT='a',RIGHT='d' };
	//节点
	struct  Point
	{
		//数据域
		int x;
		int y;

		//指针域
		Point* next;
	};

	void initSnake();

	//销毁节点
	void destroyPoint();

	//添加节点
	void addPoint(int x, int y);

	//删除节点
	void delPoint();

	//移动蛇操作
	//返回值代表移动施法成功
	bool move(char key);

	Point* pHead;

	Wall& wall;

	Food& food;
};

snake.cpp:

#include "snake.h"

Snake::Snake(Wall& tempWall, Food& tmpFood) :wall(tempWall), food(tmpFood)
{
	pHead = NULL;
}

void Snake::initSnake()
{
	destroyPoint();
	addPoint(5, 3);
	addPoint(5, 4);
	addPoint(5, 5);
}

void Snake::destroyPoint()
{
	Point* pCur = pHead;
	while (pHead != NULL)
	{
		pCur = pHead->next;
		delete pHead;
		pHead = pCur;
	}
}

void Snake::addPoint(int x, int y)
{
	//创建新节点
	Point* newPoint = new Point;
	newPoint->x = x;
	newPoint->y = y;
	newPoint->next = NULL;

	//如果原来头不为空,改为 身子
	if (pHead != NULL)
	{
		wall.setWall(pHead->x, pHead->y, '=');
	}
	newPoint->next = pHead;
	pHead = newPoint;//更新头部
	wall.setWall(pHead->x, pHead -> y, '@');
}

//删除节点
void Snake::delPoint()
{
	//两个节点以上,才去做删除操作
	if (pHead == NULL || pHead->next == NULL)
	{
		return;
	}
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	//删除尾节点
	wall.setWall(pCur->x, pCur->y, ' ');
	delete pCur;
	pCur = NULL;
	pPre->next = NULL;
}

bool Snake::move(char key)
{
	int x = pHead->x;
	int y = pHead->y;
	
	switch (key)
	{
	case UP:
		x--;
		break;
	case DOWN :
		x++;
		break;
	case LEFT:
		y--;
		break;
	case RIGHT:
		y++;
		break;
	default:
		break;
	}
	//判断用户到达位置是否成功
	if (wall.getWall(x, y) == '*' || wall.getWall(x, y) == '=')
	{
		cout << "GAME OVER!!!" << endl;
		return false;
	}
	//移动成功,分两种
	//吃到食物,未吃到食物
	if (wall.getWall(x, y) == '#')
	{
		addPoint(x, y);
		
		//重新设置食物
		food.setFood();
	}
	else
	{
		addPoint(x, y);
		delPoint();
	}
	return true;
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"
#include"snake.h"
#include"food.h"
#include<ctime>

int main()
{
	//添加随机种子
	srand((unsigned int)time(NULL));
	Wall wall;
	wall.initWall();

	Food food(wall);
	food.setFood();

	Snake snake(wall,food);
	snake.initSnake();


	wall.drawWall();
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

06 蛇移动以及bug的解决

snake.h:

#pragma once
#include<iostream>
#include"wall.h"
#include"food.h"
using namespace std;

class Snake
{
public:
	Snake(Wall & tempWall,Food & ftmpFood);

	enum{ UP = 'w',DOWN ='s',LEFT='a',RIGHT='d' };
	//节点
	struct  Point
	{
		//数据域
		int x;
		int y;

		//指针域
		Point* next;
	};

	void initSnake();

	//销毁节点
	void destroyPoint();

	//添加节点
	void addPoint(int x, int y);

	//删除节点
	void delPoint();

	//移动蛇操作
	//返回值代表移动施法成功
	bool move(char key);

	Point* pHead;

	Wall& wall;

	Food& food;

	bool isRool;//判断循环标示
};

snake.cpp:

#include "snake.h"

Snake::Snake(Wall& tempWall, Food& tmpFood) :wall(tempWall), food(tmpFood)
{
	pHead = NULL;
	isRool = false;
}

void Snake::initSnake()
{
	destroyPoint();
	addPoint(5, 3);
	addPoint(5, 4);
	addPoint(5, 5);
}

void Snake::destroyPoint()
{
	Point* pCur = pHead;
	while (pHead != NULL)
	{
		pCur = pHead->next;
		delete pHead;
		pHead = pCur;
	}
}

void Snake::addPoint(int x, int y)
{
	//创建新节点
	Point* newPoint = new Point;
	newPoint->x = x;
	newPoint->y = y;
	newPoint->next = NULL;

	//如果原来头不为空,改为 身子
	if (pHead != NULL)
	{
		wall.setWall(pHead->x, pHead->y, '=');
	}
	newPoint->next = pHead;
	pHead = newPoint;//更新头部
	wall.setWall(pHead->x, pHead -> y, '@');
}

//删除节点
void Snake::delPoint()
{
	//两个节点以上,才去做删除操作
	if (pHead == NULL || pHead->next == NULL)
	{
		return;
	}
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	//删除尾节点
	wall.setWall(pCur->x, pCur->y, ' ');
	delete pCur;
	pCur = NULL;
	pPre->next = NULL;
}

bool Snake::move(char key)
{
	int x = pHead->x;
	int y = pHead->y;
	
	switch (key)
	{
	case UP:
		x--;
		break;
	case DOWN :
		x++;
		break;
	case LEFT:
		y--;
		break;
	case RIGHT:
		y++;
		break;
	default:
		break;
	}

	//判断,如果是下一步碰到的是尾巴,不应该死亡
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	if (pCur->x == x && pCur->y == y)
	{
		//碰到尾巴 循环
		isRool = true;
	}
	else
	{
		//判断用户到达位置是否成功
		if (wall.getWall(x, y) == '*' || wall.getWall(x, y) == '=')
		{
			addPoint(x, y);
			destroyPoint();
			system("cls");
			cout << "GAME OVER!!!" << endl;
			return false;
		}
	}

	//移动成功,分两种
	//吃到食物,未吃到食物
	if (wall.getWall(x, y) == '#')
	{
		addPoint(x, y);
		
		//重新设置食物
		food.setFood();
	}
	else
	{
		addPoint(x, y);
		delPoint();
		if (isRool == true)
		{
			wall.setWall(x, y, '@');
		}
	}
	return true;
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"
#include"snake.h"
#include"food.h"
#include<ctime>
#include<conio.h>
#include<windows.h>

int main()
{
	//添加随机种子
	srand((unsigned int)time(NULL));

	//是否死亡标示
	bool isDead = false;

	char preKey = NULL;

	Wall wall;
	wall.initWall();

	Food food(wall);
	food.setFood();

	Snake snake(wall,food);
	snake.initSnake();
	wall.drawWall();

	while (!isDead)
	{
		char key = _getch();

		//判断 如果是第一次按了,左键,才不能激活游戏
		//判断上一次 移动方向
		if (preKey == NULL && key == snake.LEFT)
		{
			continue;
		}
		do {
			if (key == snake.UP || key == snake.DOWN || key == snake.LEFT || key == snake.RIGHT)
			{
				//判断本次按键是否与上次冲突
				if ((key==snake.LEFT && preKey==snake.RIGHT)||
					(key == snake.RIGHT && preKey == snake.LEFT) ||
					(key == snake.UP && preKey == snake.DOWN) || 
					(key == snake.DOWN && preKey == snake.UP) )
				{
					key = preKey;
				}
				else
				{
					preKey = key;//不是冲突按键,可以更新按键
				}
				if (snake.move(key) == true)
				{
					//移动成功  代码
					system("cls");
					wall.drawWall();
					Sleep(300);
				}
				else
				{
					isDead = true;
					break;
				}
			}
			else
			{
				key = preKey;//强制将错误按键变为 上一次移动的方向
			}
			} while (!_kbhit());//当没有键盘输入的时候,返回0

	}
	system("pause");
	return EXIT_SUCCESS;
}

07 辅助玩法、难度和分数

在这里插入图片描述
snake.h:

#pragma once
#include<iostream>
#include"wall.h"
#include"food.h"
using namespace std;

class Snake
{
public:
	Snake(Wall & tempWall,Food & ftmpFood);

	enum{ UP = 'w',DOWN ='s',LEFT='a',RIGHT='d' };
	//节点
	struct  Point
	{
		//数据域
		int x;
		int y;

		//指针域
		Point* next;
	};

	void initSnake();

	//销毁节点
	void destroyPoint();

	//添加节点
	void addPoint(int x, int y);

	//删除节点
	void delPoint();

	//移动蛇操作
	//返回值代表移动施法成功
	bool move(char key);

	//设置难度
	//获取刷屏时间
	int getSleepTime();
	//获取蛇身段
	int countList();

	//获取分数
	int getScore();

	Point* pHead;

	Wall& wall;

	Food& food;

	bool isRool;//判断循环标示
};

snake.cpp:

#include "snake.h"

Snake::Snake(Wall& tempWall, Food& tmpFood) :wall(tempWall), food(tmpFood)
{
	pHead = NULL;
	isRool = false;
}

void Snake::initSnake()
{
	destroyPoint();
	addPoint(5, 3);
	addPoint(5, 4);
	addPoint(5, 5);
}

void Snake::destroyPoint()
{
	Point* pCur = pHead;
	while (pHead != NULL)
	{
		pCur = pHead->next;
		delete pHead;
		pHead = pCur;
	}
}

void Snake::addPoint(int x, int y)
{
	//创建新节点
	Point* newPoint = new Point;
	newPoint->x = x;
	newPoint->y = y;
	newPoint->next = NULL;

	//如果原来头不为空,改为 身子
	if (pHead != NULL)
	{
		wall.setWall(pHead->x, pHead->y, '=');
	}
	newPoint->next = pHead;
	pHead = newPoint;//更新头部
	wall.setWall(pHead->x, pHead -> y, '@');
}

//删除节点
void Snake::delPoint()
{
	//两个节点以上,才去做删除操作
	if (pHead == NULL || pHead->next == NULL)
	{
		return;
	}
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	//删除尾节点
	wall.setWall(pCur->x, pCur->y, ' ');
	delete pCur;
	pCur = NULL;
	pPre->next = NULL;
}

bool Snake::move(char key)
{
	int x = pHead->x;
	int y = pHead->y;
	
	switch (key)
	{
	case UP:
		x--;
		break;
	case DOWN :
		x++;
		break;
	case LEFT:
		y--;
		break;
	case RIGHT:
		y++;
		break;
	default:
		break;
	}

	//判断,如果是下一步碰到的是尾巴,不应该死亡
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	if (pCur->x == x && pCur->y == y)
	{
		//碰到尾巴 循环
		isRool = true;
	}
	else
	{
		//判断用户到达位置是否成功
		if (wall.getWall(x, y) == '*' || wall.getWall(x, y) == '=')
		{
			addPoint(x, y);
			destroyPoint();
			system("cls");
			cout << "得分:" << getScore() << "分" << endl;
			cout << "GAME OVER!!!" << endl;
			return false;
		}
	}

	//移动成功,分两种
	//吃到食物,未吃到食物
	if (wall.getWall(x, y) == '#')
	{
		addPoint(x, y);
		
		//重新设置食物
		food.setFood();
	}
	else
	{
		addPoint(x, y);
		delPoint();
		if (isRool == true)
		{
			wall.setWall(x, y, '@');
		}
	}
	return true;
}

int Snake::getSleepTime()
{
	int sleepTime = 0;
	int size = countList();
	if (size < 5)
	{
		sleepTime = 300;
	}
	else if (size >= 5 && size <= 8)
	{
		sleepTime = 200;
	}
	else 
	{
		sleepTime = 100;
	}
	return sleepTime;
}

int Snake::countList()
{
	int size = 0;
	Point* curPoint = pHead;
	while (curPoint != NULL)
	{
		size++;
		curPoint = curPoint->next;
	}
	return size;
}

int Snake::getScore()
{
	int size = countList();
	int score = (size - 3) * 100;
	return score;
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"
#include"snake.h"
#include"food.h"
#include<ctime>
#include<conio.h>
#include<windows.h>

int main()
{
	//添加随机种子
	srand((unsigned int)time(NULL));

	//是否死亡标示
	bool isDead = false;

	char preKey = NULL;

	Wall wall;
	wall.initWall();

	Food food(wall);
	food.setFood();

	Snake snake(wall,food);
	snake.initSnake();
	wall.drawWall();

	cout << "得分:" << snake.getScore() << "分" << endl;

	while (!isDead)
	{
		char key = _getch();

		//判断 如果是第一次按了,左键,才不能激活游戏
		//判断上一次 移动方向
		if (preKey == NULL && key == snake.LEFT)
		{
			continue;
		}
		do {
			if (key == snake.UP || key == snake.DOWN || key == snake.LEFT || key == snake.RIGHT)
			{
				//判断本次按键是否与上次冲突
				if ((key==snake.LEFT && preKey==snake.RIGHT)||
					(key == snake.RIGHT && preKey == snake.LEFT) ||
					(key == snake.UP && preKey == snake.DOWN) || 
					(key == snake.DOWN && preKey == snake.UP) )
				{
					key = preKey;
				}
				else
				{
					preKey = key;//不是冲突按键,可以更新按键
				}
				if (snake.move(key) == true)
				{
					//移动成功  代码
					system("cls");
					wall.drawWall();
					cout << "得分:" << snake.getScore() << "分" << endl;
					Sleep(snake.getSleepTime());
				}
				else
				{
					isDead = true;
					break;
				}
			}
			else
			{
				key = preKey;//强制将错误按键变为 上一次移动的方向
			}
			} while (!_kbhit());//当没有键盘输入的时候,返回0

	}
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

08 优化游戏

gotoxy函数可以任意移动位置,进行输出输入。
gotoxy有一个特别有用的作用,比如,你移到第3行第2格,输出"123",但是你还想移到第1行第1格输出"123",如果不用gotoxy函数,是做不到的,但是gotoxy可以做到

void gotoxy(int x, int y) {
COORD pos = {x,y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, pos);
}

wall.h:

#ifndef _WALL_HEAD
#define _WALL_HEAD
#include<iostream>
using namespace std;

class Wall
{
public:
	enum {
		ROW = 26,
		COL = 26
	};

	//初始化墙壁
	void initWall();

	//画出墙壁
	void drawWall();

	//根据索引设置,二维数组里的内容
	void setWall(int x, int y, char c);

	//根据索引获取当前位置的符号
	char getWall(int x, int y);

private:
	char gameArray[ROW][COL];
};
#endif // !_WALL_HEAD

wall.cpp:

#include"wall.h"

void Wall::initWall()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			//放墙壁
			if (i == 0 || j == 0 || i == ROW - 1 || j == COL - 1)
			{
				gameArray[i][j] = '*';
			}
			else
			{
				gameArray[i][j] = ' '; 
			}
		}
	}
}

void Wall::drawWall()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			cout << gameArray[i][j] << " ";
		}
		if (i == 5)
		{
			cout << "create by zt";
		}
		if (i == 6)
		{
			cout << "a:left";
		}
		if (i == 7)
		{
			cout << "b:right";
		}
		if (i == 8)
		{
			cout << "w:up";
		}
		if (i == 9)
		{
			cout << "s:down";
		}
		cout << endl;
	}
}

void Wall::setWall(int x, int y, char c)
{
	gameArray[x][y] = c;
}

char Wall::getWall(int x, int y)
{
	return gameArray[x][y];
}

food.h:

#pragma once
#include<iostream>
using namespace std;
#include"wall.h"

class Food
{
public:
	Food(Wall& tempWall);
	//设置食物
	void setFood();

	int foodX;
	int foodY;

	Wall& wall;
};

food.cpp:

#include "food.h"
#include<Windows.h>

void gotoxy2(HANDLE hOut2, int x, int y) {
	COORD pos = { x,y };
	SetConsoleCursorPosition(hOut2, pos);
}

HANDLE hOut2 = GetStdHandle(STD_OUTPUT_HANDLE);//定义显示器句柄变量

Food::Food(Wall& tempWall):wall(tempWall)
{
}

void Food::setFood()
{
	while (true)
	{
		foodX = rand() % (Wall::ROW - 1) + 1;
		foodY = rand() % (Wall::COL - 1) + 1;

		//如果随机的位置是蛇头或蛇身,就重新生成随机数
		if (wall.getWall(foodX, foodY) == ' ')
		{
			wall.setWall(foodX, foodY, '#');
			gotoxy2(hOut2, foodY * 2, foodX);
			cout << "#";
			break;
		}
	}
}

snake.h:

#pragma once
#include<iostream>
#include"wall.h"
#include"food.h"
using namespace std;

class Snake
{
public:
	Snake(Wall & tempWall,Food & ftmpFood);

	enum{ UP = 'w',DOWN ='s',LEFT='a',RIGHT='d' };
	//节点
	struct  Point
	{
		//数据域
		int x;
		int y;

		//指针域
		Point* next;
	};

	void initSnake();

	//销毁节点
	void destroyPoint();

	//添加节点
	void addPoint(int x, int y);

	//删除节点
	void delPoint();

	//移动蛇操作
	//返回值代表移动施法成功
	bool move(char key);

	//设置难度
	//获取刷屏时间
	int getSleepTime();
	//获取蛇身段
	int countList();

	//获取分数
	int getScore();

	Point* pHead;

	Wall& wall;

	Food& food;

	bool isRool;//判断循环标示
};

snake.cpp:

#include "snake.h"
#include<Windows.h>

void gotoxy1(HANDLE hOut1, int x, int y) {
	COORD pos = { x,y };
	SetConsoleCursorPosition(hOut1, pos);
}

HANDLE hOut1 = GetStdHandle(STD_OUTPUT_HANDLE);//定义显示器句柄变量


Snake::Snake(Wall& tempWall, Food& tmpFood) :wall(tempWall), food(tmpFood)
{
	pHead = NULL;
	isRool = false;
}

void Snake::initSnake()
{
	destroyPoint();
	addPoint(5, 3);
	addPoint(5, 4);
	addPoint(5, 5);
}

void Snake::destroyPoint()
{
	Point* pCur = pHead;
	while (pHead != NULL)
	{
		pCur = pHead->next;
		delete pHead;
		pHead = pCur;
	}
}

void Snake::addPoint(int x, int y)
{
	//创建新节点
	Point* newPoint = new Point;
	newPoint->x = x;
	newPoint->y = y;
	newPoint->next = NULL;

	//如果原来头不为空,改为 身子
	if (pHead != NULL)
	{
		wall.setWall(pHead->x, pHead->y, '=');
		gotoxy1(hOut1, pHead->y * 2, pHead->x);
		cout << "=";
	}
	newPoint->next = pHead;
	pHead = newPoint;//更新头部
	wall.setWall(pHead->x, pHead -> y, '@');
	gotoxy1(hOut1, pHead->y * 2, pHead->x);
	cout << "@";
}

//删除节点
void Snake::delPoint()
{
	//两个节点以上,才去做删除操作
	if (pHead == NULL || pHead->next == NULL)
	{
		return;
	}
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	//删除尾节点
	wall.setWall(pCur->x, pCur->y, ' ');
	gotoxy1(hOut1, pCur->y * 2, pCur->x);
	cout << " ";
	delete pCur;
	pCur = NULL;
	pPre->next = NULL;
}

bool Snake::move(char key)
{
	int x = pHead->x;
	int y = pHead->y;
	
	switch (key)
	{
	case UP:
		x--;
		break;
	case DOWN :
		x++;
		break;
	case LEFT:
		y--;
		break;
	case RIGHT:
		y++;
		break;
	default:
		break;
	}

	//判断,如果是下一步碰到的是尾巴,不应该死亡
	Point* pCur = pHead->next;
	Point* pPre = pHead;

	while (pCur->next != NULL)
	{
		pPre = pPre->next;
		pCur = pCur->next;
	}
	if (pCur->x == x && pCur->y == y)
	{
		//碰到尾巴 循环
		isRool = true;
	}
	else
	{
		//判断用户到达位置是否成功
		if (wall.getWall(x, y) == '*' || wall.getWall(x, y) == '=')
		{
			//addPoint(x, y);
			//destroyPoint();
			system("cls");
			cout << "得分:" << getScore() << "分" << endl;
			cout << "GAME OVER!!!" << endl;
			return false;
		}
	}

	//移动成功,分两种
	//吃到食物,未吃到食物
	if (wall.getWall(x, y) == '#')
	{
		addPoint(x, y);
		
		//重新设置食物
		food.setFood();
	}
	else
	{
		addPoint(x, y);
		delPoint();
		if (isRool == true)
		{
			wall.setWall(x, y, '@');
			gotoxy1(hOut1, pHead->y * 2, pHead->x);
			cout << "@";
		}
	}
	return true;
}

int Snake::getSleepTime()
{
	int sleepTime = 0;
	int size = countList();
	if (size < 5)
	{
		sleepTime = 300;
	}
	else if (size >= 5 && size <= 8)
	{
		sleepTime = 200;
	}
	else 
	{
		sleepTime = 100;
	}
	return sleepTime;
}

int Snake::countList()
{
	int size = 0;
	Point* curPoint = pHead;
	while (curPoint != NULL)
	{
		size++;
		curPoint = curPoint->next;
	}
	return size;
}

int Snake::getScore()
{
	int size = countList();
	int score = (size - 3) * 100;
	return score;
}

game.cpp:

#include<iostream>
using namespace std;
#include"wall.h"
#include"snake.h"
#include"food.h"
#include<ctime>
#include<conio.h>
#include<windows.h>

void gotoxy(HANDLE hOut,int x, int y) {
	COORD pos = { x,y };
	SetConsoleCursorPosition(hOut, pos);
}

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//定义显示器句柄变量


int main()
{
	//添加随机种子
	srand((unsigned int)time(NULL));

	//是否死亡标示
	bool isDead = false;

	char preKey = NULL;

	Wall wall;
	wall.initWall();
	wall.drawWall();

	Food food(wall);
	food.setFood();

	Snake snake(wall,food);
	snake.initSnake();

	gotoxy(hOut, Wall::COL * 2, Wall::ROW);//y*2  y
	cout << "得分:" << snake.getScore() << "分" << endl;

	while (!isDead)
	{
		char key = _getch();

		//判断 如果是第一次按了,左键,才不能激活游戏
		//判断上一次 移动方向
		if (preKey == NULL && key == snake.LEFT)
		{
			continue;
		}
		do {
			if (key == snake.UP || key == snake.DOWN || key == snake.LEFT || key == snake.RIGHT)
			{
				//判断本次按键是否与上次冲突
				if ((key==snake.LEFT && preKey==snake.RIGHT)||
					(key == snake.RIGHT && preKey == snake.LEFT) ||
					(key == snake.UP && preKey == snake.DOWN) || 
					(key == snake.DOWN && preKey == snake.UP) )
				{
					key = preKey;
				}
				else
				{
					preKey = key;//不是冲突按键,可以更新按键
				}
				if (snake.move(key) == true)
				{
					//移动成功  代码
					//system("cls");
					//wall.drawWall();
					gotoxy(hOut, Wall::COL * 2, Wall::ROW );
					cout << "得分:" << snake.getScore() << "分" << endl;
					Sleep(snake.getSleepTime());
				}
				else
				{
					isDead = true;
					break;
				}
			}
			else
			{
				key = preKey;//强制将错误按键变为 上一次移动的方向
			}
			} while (!_kbhit());//当没有键盘输入的时候,返回0

	}
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值