//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
}
}