C++day14---STL实现贪吃蛇

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

在这里插入图片描述

//wall.h
#pragma once
#ifndef _WALL_HEAD
#define _WALL_HEAD
#include <iostream>
using namespace std;

class Wall {
public:
	enum {
		ROW = 26,
		COL = 26,
	};
	//初始化墙壁
	void initWall();
	//展示墙壁
	void draw();
	//根据索引设置二维数组里的内容
	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::draw()
{
	for (int i = 0; i < ROW; ++i) {
		for (int j = 0; j < COL; ++j) {
			cout << gameArray[i][j] << " ";
		}
		if (i == 5)
			cout << "created by charon";
		else if (i == 6)
			cout << "a: left";
		else if (i == 7)
			cout << "d: right";
		else if (i == 8)
			cout << "w: up";
		else 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];
}

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

//snake.h
#pragma once
#include <iostream>
#include "wall.h"
using namespace std;
class Snake {
public:
	Snake(Wall& temp);
	struct Point {
		//数据域
		int x, y;
		//指针域
		Point* next;
	};
	Point* pHead;//头结点
	Wall& wall;//维护成员
	//初始化
	void initSnake();
	//销毁节点
	void destroyPoint();
	//添加节点
	void addPoint(int x, int y);
	//删除节点
	void delPoint();
};
//snake.cpp
#include "snake.h"

//保证拿到main函数中的同一个wall
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 (pCur != 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;
}

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

//food.h
#pragma once
#include <iostream>
using namespace std;
#include "snake.h"
class Food {
public:
	Food(Wall& temp);
	int foodX, foodY;
	//设置食物
	Wall& wall;
	void setFood();
};
//food.cpp
#include "food.h"

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

void Food::setFood()
{
	while (true) {
		foodX = rand() % (Wall::ROW - 2) + 1;//保证随机生成的点处于1-12的单元格内
		foodY = rand() % (Wall::COL - 2) + 1;
		//如果随机的位置是蛇头或蛇神 就重新生成
		if (wall.getWall(foodX, foodY) == ' ') {
			wall.setWall(foodX, foodY, '#');
			break;
		}
	}
}

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

//snake.h
#pragma once
#include <iostream>
#include "wall.h"
#include "food.h"
using namespace std;
class Snake {
public:
	Snake(Wall& tempWall, Food& tempFood);
	enum {
		UP = 'w', DOWN = 's', LEFT = 'a', RIGHT = 'd'
	};
	struct Point {
		//数据域
		int x, y;
		//指针域
		Point* next;
	};
	Point* pHead;//头结点
	Wall& wall;//维护成员
	Food& food;
	bool isRool;//判断循环标识
	//初始化
	void initSnake();
	//销毁节点
	void destroyPoint();
	//添加节点
	void addPoint(int x, int y);
	//删除节点
	void delPoint();
	//移动蛇,返回值代表移动是否成功
	bool move(char key);
};
//snake.cpp
#include "snake.h"

//保证拿到main函数中的同一个wall
Snake::Snake(Wall&tempWall, Food&tempFood):wall(tempWall), food(tempFood)
{
	pHead = NULL;
	isRool = false;
}

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

//销毁所有的节点
void Snake::destroyPoint()
{
	Point* pCur = pHead;
	while (pCur != 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) {
		//碰到尾巴,循环
		isRool = true;
	}
	else {
		//判断用户到达位置是否成功
		if (wall.getWall(x, y) == '*' || wall.getWall(x, y) == '=') {
			addPoint(x, y);//多走一步
			delPoint();
			system("cls");
			wall.draw();
			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;
}
//main.cpp
#define _CRT_SECURE_NO_WARNINGS
#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;
	Food food(wall);
	Snake snake(wall,food);
	wall.initWall();
	food.setFood();
	snake.initSnake();

	wall.draw();
	//接收用户输入
	while (!isDead)
	{
		char key = _getch();
		//判断如果是第一次按左键,则不能激活游戏
		//判断上一次移动方向
		if (NULL == preKey && key == snake.LEFT)
			continue;

		do {
			//只允许上下左右键
			if (key == snake.UP || key == snake.DOWN || key == snake.LEFT || key == snake.RIGHT) {
				//判断本次的按键是否与上次冲突,比如移动方向为右,当按A时应该使本次失效
				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;//不是冲突按键,直接更新
				
				preKey = key;
				if (true == snake.move(key)) {
					//移动成功
					system("cls");
					wall.draw();
					Sleep(100);
				}
				else {
					isDead = true;
					break;
				}
			}
			else {
				key = preKey;//强制将错误按键变为上一次移动方向
			}
		} while (!_kbhit());//当没有键盘输入的时候,返回0
	}
}

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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值