利用C++设计简单的控制台贪吃蛇游戏.
第一步:设计地图类:
class Map
{
private:
public:
enum{MAPX = 10, MAPY = 2};
enum{ROW = 20, COL = 40};
char map[ROW][COL]; //地图
Map();
void DrawMap(); //绘制地图
bool IsVaildPoint(int x, int y);
};
1.利用枚举来定义常量,在类外部可以通过作用域解析来获取枚举常量,便于所有类的交流.
2.通过二维数组存储地图,在构造的时候读取并绘制地图,
3.定义一个外部接口,用于判断点是否在地图上.
第二步:设计甜点类
class Snack;
class Dessert
{
private:
int mark; //分数
char figure;
public:
int x;
int y;
Dessert(int mark = 10, const char str = '$');
~Dessert(void);
void DrawDessert(); //绘制图形
int GetMark(){return mark;} //获得积分
void MakeNewDessert(const Snack &snack);
};
1.使用前向声明,让编译器知道Snack类的存在
2. MakeNewDessert更新甜点.
第三步:设计蛇类
class Dessert;
class Map;
class Point
{
public:
int x;
int y;
void Draw(char ch)const
{
gotoxy(y, x);
putchar(ch);
}
};
class Snack
{
private:
int len; //蛇身的长度
int MaxOpp; //最大缓存操作
vector<Point> Body; //蛇身,默认蛇头为下标最大的点
int v; //速度
Move dirction;
queue<Move> moves; //操作队列
int num_moves;
public:
Snack(int v = 200);
~Snack(void);
Point & operator[](int i)
{
return this->Body[i];
}
bool isBody(int x, int y)const; //是否是蛇身的一部分
//移动蛇身
int MoveBody(Map &map, Dessert &d);
//操作符入队列
void InMoves(Move d);
int GetV(){return v;};
};
1.使用队列缓存操作.
2.蛇要移动的时候,先从操作队列中读取操作,如果为空,默认移动的方向为当前的方向.
参考代码:
int Snack::MoveBody(Map &map, Dessert &d)
{
Point p;
const Point &head = Body[len - 1]; //蛇头
const Point &tail = Body.front(); //蛇尾
Move move;
bool flag = false; //标示是否有操作
while(!moves.empty())
{
move = moves.front();
moves.pop();
this->num_moves--;
if(isReverseDirection(move, this->dirction))
continue;
else
{
flag = true;
break;
}
}
if(!flag) //没有操作时自动行走
move = this->dirction;
this->dirction = move; //更新运动方向
switch(move)
{
case UP:
p.x = head.x - 1;
p.y = head.y;
break;
case RIGHT:
p.x = head.x;
p.y = head.y + 1;
break;
case DOWN:
p.x = head.x + 1;
p.y = head.y;
break;
case LEFT:
p.x = head.x;
p.y = head.y - 1;
break;
}
if(!map.IsVaildPoint(p.x, p.y) || this->isBody(p.x, p.y))
{
return 0; //失败
}
p.Draw('#'); //画新蛇头
head.Draw('*'); //更新旧蛇头
if(d.x == p.x && d.y == p.y)
{
Body.push_back(p); //蛇身增长
len++;
return 1; //吃到东西
}
tail.Draw(' '); //去掉旧蛇尾
for(int i = 0; i < len - 1; i++)
{
Body[i] = Body[i + 1];
}
Body[len - 1] = p;
return 2;
}
void Snack::InMoves(Move d)
{
if(this->num_moves >= this->MaxOpp)
return;
this->moves.push(d);
this->num_moves++;
}
第四步:设计游戏类
class GamePlayer
{
private:
int mark; //分数
int lvl; //当前关数
int getPress(); //获得按键符合
public:
Map map; //地图
Snack snack; //蛇
Dessert dessert; //甜点
GamePlayer(void);
~GamePlayer(void);
void PressHandle();
void WaitStart();
bool isEnd(){return false;};
int Getv(){return snack.GetV();};
void MoveHandle();
void updateMark();
int getMark(){return mark;};
};
1. 把游戏逻辑的处理交给游戏类
2. PressHandle();处理按键输入和执行
3. getPress();是内部方法,应该隐藏起来
4. MoveHandle();处理蛇身移动
第五步:测试游戏
#include <iostream>
#include <conio.h>
#include <cstdlib>
#include "GamePlayer.h"
#include <cstdlib>
#include <time.h>
#include <cstdio>
using namespace std;
int main()
{
srand((unsigned)time(0));
hideCursor();
GamePlayer game;
while(!game.isEnd())
{
long start;
start = clock(); /*record the start time */
while((clock() - start) <= game.Getv()) //固定时间
{
if(kbhit())
game.PressHandle();
}
game.MoveHandle();
}
cin.get();
return 0;
}