总体思路是不断维护一个二维字符数组,不断更新二维字符串数组,并不断清屏,显示到控制台上
主函数
#include <iostream>
#include <ctime>
#include <Windows.h>
#include <conio.h>
#include "BackGround.h"
#include "Food.h"
#include "Snake.h"
int main()
{
srand(unsigned int(time(NULL)));
bool isDead = false;
BackGround bg;
bg.initBackGround();
Food food(bg);
Snake snake(bg,food);
snake.initSnake();
food.setFood();
bg.DrawBackGround();
char preKey = NULL;
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 = preKey;
else if (key == snake.RIGHT && preKey == snake.LEFT)
key = preKey;
else if (key == snake.UP && preKey == snake.DOWN)
key = preKey;
else if (key == snake.DOWN && preKey == snake.UP)
key = preKey;
else {
preKey = key;
}
if (snake.move(key)) {
system("cls");
bg.DrawBackGround();
Sleep(300);
}
else {
isDead = true;
break;
}
}
else {
key = preKey;
}
} while (!_kbhit());
}
}
BackGround.h
可以将ROW和COL设为静态变量
#pragma once
class BackGround
{
public:
enum {
ROW = 26,
COL = 26
};
BackGround() {};
~BackGround() {};
void initBackGround();
void DrawBackGround();
void setBackGround(int x, int y, char c);
char getBackGround(int x, int y);
private:
char gameArray[ROW][COL];
};
BackGround.cpp
#include "BackGround.h"
#include <iostream>
void BackGround::initBackGround() {
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 BackGround::DrawBackGround()
{
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
std::cout << gameArray[i][j] << " ";
}
if ( i == 5)
std::cout << "create by XieYang";
if (i == 6)
std::cout << "a : left";
if (i == 7)
std::cout << "d : left";
if (i == 8)
std::cout << "w : top";
if (i == 9)
std::cout << "s : buttom";
std::cout << std::endl;
}
}
void BackGround::setBackGround(int x, int y, char c)
{
gameArray[x][y] = c;
}
char BackGround::getBackGround(int x, int y)
{
return gameArray[x][y];
}
因为food类也需要使用背景,所以使用委托的设计方法,放一个对象的引用(或指针)
food.h
#pragma once
#include <iostream>
#include "BackGround.h"
class Food
{
private:
BackGround &bg;
public:
Food(BackGround &bg_);
~Food();
void setFood();
int foodX;
int foodY;
};
food.cpp
#include "Food.h"
Food::Food(BackGround &bg_):bg(bg_)
{
}
Food::~Food()
{
}
void Food::setFood()
{
while (true) {
foodX = rand() % (BackGround::ROW - 2) + 1;
foodY = rand() % (BackGround::COL - 2) + 1;
if (bg.getBackGround(foodX, foodY) == ' ') {
bg.setBackGround(foodX, foodY, '#');
break;
}
}
}
蛇的实现是用一个链表实现的,Snake.h,蛇的类的设计同样采用委托的方法,传入BackGround和Food类的引用。
#include "Food.h"
class Snake
{
private:
struct Point {
int x;
int y;
Point* next;
Point(int x_,int y_):x(x_),y(y_),next(nullptr){}
};
Point* pHead;
BackGround & bg;
Food & food;
public:
enum { UP = 'w', DOWN = 's', LEFT = 'a', RIGHT = 'd' };
Snake(BackGround &bg_, Food & food);
~Snake();
void initSnake();
void destroyPoint();
void addPoint(int x,int y);
void delPoint();
bool move(char key);
};
蛇的移动只是坐标的变化,注意,这里坐标的变化只是改变蛇头,即新添加一个节点到蛇头,如果吃到食物,就不变,如果没有吃到,那么就删除蛇尾,那么就涉及到链表的基本操作。另外,为了规则的方便,还可以维护一个蛇头方向的变量
#include "Snake.h"
Snake::Snake(BackGround &bg_, Food &food_): bg(bg_),pHead(nullptr),food(food_)
{
}
Snake::~Snake()
{
Point* pCur = pHead;
while (pHead) {
pCur = pHead->next;
delete pHead;
pHead = pCur;
}
}
void Snake::initSnake()
{
destroyPoint();
addPoint(5, 3);
addPoint(5, 4);
addPoint(5, 5);
}
void Snake::destroyPoint()
{
Point* pCur = pHead;
while (pHead) {
pCur = pHead->next;
delete pHead;
pHead = pCur;
}
}
void Snake::addPoint(int x, int y)
{
Point* newPoint = new Point(x, y);
if (pHead != nullptr) {
bg.setBackGround(pHead->x, pHead->y, '=');
}
newPoint->next = pHead;
pHead = newPoint;
bg.setBackGround(pHead->x, pHead->y, '@');
}
void Snake::delPoint()
{
if (pHead == nullptr || pHead->next == nullptr)
return;
Point* pCur = pHead->next;
Point* pPre = pHead;
while (pCur->next) {
pPre = pPre->next;
pCur = pCur->next;
}
bg.setBackGround(pCur->x, pCur->y, ' ');
delete pCur;
pCur = nullptr;
pPre->next = nullptr;
}
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:
return true;
break;
}
if (bg.getBackGround(x, y) == '*' || bg.getBackGround(x, y) == '=')
return false;
if (bg.getBackGround(x, y) == '#') {
addPoint(x, y);
food.setFood();
}
else {
addPoint(x,y);
delPoint();
}
return true;
}