利用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;
}