C++控制台坦克大战
最近接了一个企业的C++定制培训班,在语法阶段结束后要求带学生做一个项目。思来想去就做一个控制台的坦克大战吧,在这里分享给大家。
工具类
- 坐标点类
class Point
{
public:
Point();
Point(int x, int y);
inline int getX(){return x;}
inline int getY(){return y;}
inline void setX(int x){this->x = x;}
inline void setY(int y){this->y = y;}
bool operator==(const Point& other);
Point operator+(Point other);
private:
int x;
int y;
};
2.尺寸类
class Size
{
public:
Size();
Size(int width, int height);
inline int getWidth(){return width;}
inline int getHeight(){return height;}
inline void setWidth(int width){this->width = width;}
inline void setHeight(int height){this->height = height;}
bool operator==(const Size& other);
private:
int width;
int height;
};
3.矩形类
class Rect
{
public:
Rect();
Rect(Point pos, Size size);
inline Point getPos(){return pos;}
inline Size getSize(){return size;}
inline void setPos(Point pos){this->pos = pos;}
inline void setSize(Size size){this->size = size;}
bool contains(Point point);
bool collide(Rect other);
int minX();
int maxX();
int minY();
int maxY();
private:
Point pos;
Size size;
};
类的继承关系
- 继承关系图
- Sprite类
class Sprite
{
public:
Sprite();
public:
virtual void draw() = 0;
virtual void clearDraw() = 0;
virtual void update() = 0;
inline Rect getRect(){return Rect(pos, size);}
inline Point getPos(){return pos;}
inline Size getSize(){return size;}
inline void setPos(Point pos){this->pos = pos;}
inline void setSize(Size size){this->size = size;}
protected:
Point pos;
Size size;
};
- Role类
class Role : public Sprite
{
public:
Role();
enum Direction_t
{
dir_up,
dir_down,
dir_left,
dir_right
};
virtual void moveUp()=0;
virtual void moveDown()=0;
virtual void moveLeft()=0;
virtual void moveRight()=0;
inline void setSpeed(int speed){this->speed = speed;}
inline void setDirection(Direction_t dir){direction = dir;}
inline Direction_t getDirection(){return direction;}
protected:
Direction_t direction;
int speed;
int speedCount;
};
- Barrier类
class Barrier : public Sprite
{
public:
Barrier(char type);
void draw();
void clearDraw();
void update();
private:
int status;
string body[3][2] = {
{"# #","# #"},
{"@ @","@ @"},
{"$ $","$ $"}
};
};
- Hero类
class Hero : public Role
{
public:
Hero();
void draw();
void clearDraw();
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
void update();
void fire();
bool canFire();
bool canMove();
bool collideBarrier();
bool collideBarrier(Point newPos);
private:
string body[4][3] = {
{"◢ ┃ ◣","┣ ● ┫","◥ ━ ◤"},
{"◢ ━ ◣","┣ ● ┫","◥ ┃ ◤"},
{"◢ ┳ ◣","━ ● ┃","◥ ┻ ◤"},
{"◢ ┳ ◣","┃ ● ━","◥ ┻ ◤"}
};
int fireCD = 20;
int fireCDCount = 0;
};
- Enemy类
class Enemy : public Role
{
public:
Enemy();
~Enemy();
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
void draw();
void clearDraw();
void update();
bool collideBarrier();
bool collideBarrier(Point newPos);
private:
void moveCtrl();
void fireCtrl();
void changeDirection();
private:
string body[4][3] = {
{"╔ ┃ ╗","╠ █ ╣","╚ ╩ ╝"},
{"╔ ╦ ╗","╠ █ ╣","╚ ┃ ╝"},
{"╔ ╦ ╗","━ █ ╣","╚ ╩ ╝"},
{"╔ ╦ ╗","╠ █ ━","╚ ╩ ╝"}
};
enum Status_t
{
statusMove,
statusStop
};
int fireCD = 200;
int fireCDCount = 0;
Status_t status;
};
7 .Bullet类
class Bullet : public Role
{
public:
enum Status_t
{
heroBullet,
enemyBullet
};
Bullet(Status_t status);
~Bullet();
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
void draw();
void clearDraw();
void update();
bool collideStaticBarrier(Point newPoint);
bool collideDynamicBarrier(Point newPoint);
bool collideHomeBarrier(Point newPoint);
bool collideBarrier(Point newPoint, char type);
private:
string show = "◎";
Status_t status;
};
Scene类
Scane类主要是负责游戏主逻辑。也是观察者模式的接受者,处理各种信号。
- 游戏主逻辑:主要函数run在main函数中调用
int Scene::run()
{
draw();
while(isRun)
{
createEnemy();
keyboard();
rolesUpdate();
collideEnemy();
collideHero();
gameWin();
Sleep(50);
}
getchar();
return overFlag;
}
-
draw函数 draw函数没有在循环中调用,因为控制台打印信息很多,刷新屏幕会闪,所以采用局部刷新,每个移动物体在移动时自行刷新。 -
获得按键信息
void Scene::keyboard()
{
if (GetAsyncKeyState(VK_UP)& 0x8000)
keyboardEvent(KEY_UP);
else if (GetAsyncKeyState(VK_DOWN)& 0x8000)
keyboardEvent(KEY_DOWN);
else if (GetAsyncKeyState(VK_LEFT)& 0x8000)
keyboardEvent(KEY_LEFT);
else if (GetAsyncKeyState(VK_RIGHT)& 0x8000)
keyboardEvent(KEY_RIGHT);
else if (GetAsyncKeyState( 0x1B )& 0x8000)
exit(0);
else if (GetAsyncKeyState( 0x20 )& 0x8000)
keyboardEvent(KEY_SPACE);
}
SignalManager类
观察者模式类,用来解耦
class Receiver;
class SignalManager
{
public:
enum Signal_t
{
enemyFire,
heroBulletOutRange,
enemyBulletOutRange,
heroBulletCollideDynamicBarrier,
enemyBulletCollideDynamicBarrier,
bulletCollideHomeBarrier
};
void sendSignal(SignalManager::Signal_t signal, void* sender, void* data);
void addSignal(SignalManager::Signal_t signal, Receiver* receiver);
void removeSignal(SignalManager::Signal_t signal, Receiver* receiver);
private:
map<Signal_t, vector<Receiver*> > receivers;
void dispatch(SignalManager::Signal_t signal, void* sender, void* data);
public:
static SignalManager* getInstance();
static void releaseInstance();
private:
SignalManager();
~SignalManager();
static SignalManager* instance;
};
class Receiver
{
public:
virtual void receive(SignalManager::Signal_t signal, void* sender, void* data) = 0;
};
Utils 关卡信息和控制台window操作
- 关卡信息
char map1[SCREEN_HEIGHT][SCREEN_WIDTH+1] = {
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" @1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1 ",
" 11111111111111111111111111111111111111111111 ",
" ",
" ",
" ",
" ",
" ",
" @1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1 ",
" 11111111111111111111111111111111111111111111 ",
" ",
" ",
" ",
" ",
" ",
" #0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 ",
" 00000000000000000000000000000000000000000000 ",
" ",
" ",
" ",
" @1@1@1 ",
" 111111 ",
" @1$2@1 ",
" 112211 "
};
char map2[SCREEN_HEIGHT][SCREEN_WIDTH+1] = {
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" @1 @1 ",
" 11 11 ",
" @1 @1 ",
" 11 11 ",
" @1@1@1@1@1@1@1 ",
" 11111111111111 ",
" @1 @1 ",
" 11 11 ",
" @1 @1 ",
" 11 11 ",
" ",
" ",
" ",
" ",
" ",
" ",
" @1@1@1 ",
" 111111 ",
" @1$2@1 ",
" 112211 "
};
char (*maps[])[SCREEN_WIDTH+1] = {map1, map2};
int level = 0;
char(*currentMap)[SCREEN_WIDTH+1] = maps[level];
- 控制台移动光标
void goToPosition(Point pos)
{
COORD coord;
coord.X=pos.getX()*2+START_X;
coord.Y=pos.getY()+START_Y;
HANDLE a=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(a,coord);
}
void hideCursor()
{
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
最后附上源码:源码下载
|