高级程序设计——打飞机小游戏

时间:2021-12-31 01:00:10

实验报告(151220129 吴政亿)

一、实验要求

课程设计一

设计一个基于控制台的飞机游戏。
要求:
1. 包含玩家飞机、敌机、子弹等元素。
2. 设计过程中考虑向MFC显式的扩展性。
3. 鼓励设计其他包含交互操作的小游戏。

上传时请只上传项目文件、代码文件以及其他编译必须的文件,不要包含项目编译过程中生成的中间文件。提交文件大小限制为40MB。

课程设计二

  1. 要求在课程设计一的基础上,以windows编程、事件驱动的程序设计为基础,实现一个带有GUI界面的程序设计。
  2. 请注意保持与课程设计一的一致性。在程序设计过程中注意思考与课程设计一的联系,并尝试复用之前的代码。
  3. 如有其他设计题目、或者希望使用其他的编程环境(比如QT或者IOS等),请单独与我联系。
  4. 请使用word/txt完成实验报告一份,主要描述课程设计一和二的设计实现过程,建议包括以下内容:
    1. 课程设计的内容和目标。
    2. 类层次关系和实现。
    3. 课程设计一和二的关联和衔接。
    4. 遇到的问题和思考。

上传时请只上传实验报告、项目文件、代码文件以及其他编译必须的文件,不要包含项目编译过程中生成的中间文件。请注意提交最大大小为40MB。

学期结束前(6月24日)将安排课堂报告展示环节,建议提前做好准备。

二、设计目标

课程设计一

定义了三个类(Face、Game、Pos),结构关系如下所示

//定义界面类,负责开始界面等
class Face
{
friend class POS;
public:
Face();
~Face();
static void drawPlaying();//绘制游戏界面
static int drawWelcome();//绘制欢迎界面
static void drawMyPlane(int x, int y);//绘制我方飞机
static void drawEmeyPlane(int x, int y);//绘制敌方飞机
};
//定义游戏类
class Game
{

public:
COORD position[10];
COORD bullet[10];
Frame enemy[8];
int score;
int rank;
int rankf;
string title;
int flag_rank;

Game();

//初始化所有
void initPlane();
void initBullet();
void initEnemy();

//初始化其中一个
//void initThisBullet( COORD );
//void initThisEnemy( Frame );

void planeMove(char);
void bulletMove();
void enemyMove();

//判断碰撞函数
bool judgeCoordInFrame(Frame frame, COORD spot);

//填充所有
void drawPlane();
void drawPlaneToNull();
void drawBullet();
void drawBulletToNull();
void drawEnemy();
void drawEnemyToNull();

//填充其中一个
void drawThisBulletToNull(COORD);
void drawThisEnemyToNull(Frame);

void Pause();//游戏暂停
void Playing();//游戏开始
void judgePlane();//判断飞机是否坠毁
void judgeEnemy();//判断敌机是否坠毁
void Shoot();//射击
void GameOver();//游戏结束
void printScore();//打印得分
};
typedef struct
{
COORD position[11];
int flag;
}Frame;
//在POS中主要封装了对光标和坐标的一些操作
class POS
{

public:
//移动光标
static void SetPos(COORD a);
//移动光标
static void SetPos(int i, int j);
//隐藏光标
static void HideCursor();
//把第y行,[x1, x2) 之间的坐标填充为 ch
static void drawRow(int y, int x1, int x2, char ch);
//在a, b 纵坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
static void drawRow(COORD a, COORD b, char ch);
//把第x列,[y1, y2] 之间的坐标填充为 ch
static void drawCol(int x, int y1, int y2, char ch);
//在a, b 横坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
static void drawCol(COORD a, COORD b, char ch);
//左上角坐标、右下角坐标、用row填充行、用col填充列
static void drawFrame(COORD a, COORD b, char row, char col);
//左上角坐标(x1,y1)、右下角坐标(x2,y2)、用row填充行、用col填充列
static void drawFrame(int x1, int y1, int x2, int y2, char row, char col);
static void drawFrame(Frame frame, char row, char col);
//生成随机数a到b
static int random(int a, int b);
//在a,b定义的矩形中随机生成一点
static COORD random(COORD a, COORD b);
};

我将本游戏划分为三个对象,一个对象是界面对象Face,负责欢迎界面等绘制,由于控制台的特性,我需要单独封装一个Pos类来实现各种操作如光标移动等,最后游戏被我单独封装成一个类。

其中,Game类使用Face类成员函数,Face类使用Pos类成员函数。

课程设计二

在课程设计二我使用了QT Creator 结合C++进行了打飞机小游戏的GUI设计,由于界面的实现,在课程设计一中的Face类和Pos类在QT Creator中没有意义,因此我的打飞机小游戏GUI版主要为两个类,分别对应了两个不同的ui界面。

欢迎界面

高级程序设计——打飞机小游戏

在中间的两个按钮分别对应两个事件,这决定了敌方飞机飞行的速度为5还是10.

游戏界面

高级程序设计——打飞机小游戏

可见,右侧显示了一系列信息,击落敌机的数量,得分以及获得的称号。随着分数的上升称号变为中级飞行员到高级飞行员。
在操作飞机上,我使用了QT的私有槽函数

void keyPressEvent(QKeyEvent *k);

这个函数负责接收我的键盘信息,提供飞机上下左右飞行、射击等等,具体可以看上图右下角的操作方式。

另外,我使用了QT的QObject类封装的Timer类来实现程序的一系列时钟问题,槽函数如下:

void timerEvent(QTimerEvent *event);

这个槽函数不断的接受时间事件。在本游戏中,我有一个timeid = startTimer(50); 来负责最基础的时钟功能,每触发一次,控制所有敌方飞机向前飞翔,控制子弹前进,并且判断是否有碰撞,代码如下。

// 子弹移动
for(int i=0;i<NUM_buttle;i++){
if(!buttle[i]->isHidden()){
if(buttle[i]->y() < -100)
buttle[i]->hide();
else
buttle[i]->move(buttle[i]->x(),buttle[i]->y()-Value_buttle);
}
}
judgebullet();
judgeplane();
//敌机移动
for(int j=0;j<NUM_enemy;j++){
if(!enemy[j]->isHidden()){
if(enemy[j]->y()>660){
enemy[j]->move(random(0,630),random(-200,-100));
}
else
enemy[j]->move(enemy[j]->x(),enemy[j]->y()+Value_enemy);
}
}
//刷新称号
if(score > 200 && score < 1000)
ui->honor->setText(QString("中级飞行员"));
else if(score > 1000)
ui->honor->setText(QString("高级飞行员"));

另外一个时钟是负责爆炸效果的显示,一开始我使用了QT中的QMovie类,播放我在网上下载的boom.gif

高级程序设计——打飞机小游戏

但是这里会出现一个非常严重的问题,就是它的背景黑色部分无法去除,而且无法随着飞机的大小变换自己的大小,因此我采取了另一种较为折衷(low)的办法,就是先使用PS将gif图每一帧单独保存为png格式并且除去他们的背景,然后在触发爆炸后,先得到爆炸发生的位置与大小,然后用QLabel控件在相应的位置播放爆炸效果图,设置一个时钟boomid=startTimer(100); 每触发一次将它的播放的当前帧转化为下一帧,最后结束。

三、课程设计一和二的关联衔接

在两次设计中,由于第一次课程设计的思路比较清晰,封装的比较好,在第二次课程设计中代码复用的比较简单。

Created with Raphaël 2.1.0 课程设计一 课程设计一 课程设计二 课程设计二 包含Pos、Face、Game类 包含Dialog类与Mainwindow类 Pos类与Face类由ui界面代替 之前的光标操作变为对ui控件的操作 Game类提升为Dialog类 飞机的射击、移动等转化为事件控制

在课程设计二中、在游戏类中整体的封装依旧与课程设计一保持一致性:

    void initPlane();
void initLabel();
void initEnemy();
void initButtle();
void restart();
int timeid;
int boomid;

void judgeplane();
void judgebullet();
void shoot();
void pause();
void gameover();

四、思考总结

在本次实验中,深切体会到了老师上课所讲的有关代码复用以及封装等知识。只要前期思路清晰,封装得当,在后期写界面的时候代码复用十分方便。并且整体的构架不变。另外在本次实验中,也学习到了不少QT的知识,如控件背景透明、图片拉伸,时间事件使用等等,受益匪浅。

五、代码清单

课程设计一

Face.h

#pragma once
#include"pos.h"
class Face
{
friend class POS;
public:
Face();
~Face();
static void drawPlaying();
static int drawWelcome();
static void drawMyPlane(int x, int y);
static void drawEmeyPlane(int x, int y);
};

Face.cpp

#include "Face.h"
Face::Face()
{
}

Face::~Face()
{
}

void Face::drawPlaying()
{
POS::drawFrame(0, 0, 48, 24, '=', '|');// draw map frame;
POS::drawFrame(49, 0, 79, 4, '-', '|');// draw output frame
POS::drawFrame(49, 4, 79, 9, '-', '|');// draw score frame
POS::drawFrame(49, 9, 79, 20, '-', '|');// draw operate frame
POS::drawFrame(49, 20, 79, 24, '-', '|');// draw other message frame
POS::SetPos(52, 6);
cout << "得分:";
POS::SetPos(52, 7);
cout << "称号:";
POS::SetPos(52, 10);
cout << "操作方式:";
POS::SetPos(52, 12);
cout << " a,s,d,w 控制战机移动。";
POS::SetPos(52, 14);
cout << " p 暂停游戏。";
POS::SetPos(52, 16);
cout << " e 退出游戏。";
POS::HideCursor();
}

int Face::drawWelcome()
{
int level = -1;
POS::drawFrame(0, 0, 79, 24, '=', '|');// draw map frame;
POS::SetPos(15, 10);
cout << "请输入您选择的难度级别,级别为1-100" ;
POS::SetPos(30, 11);
cin >> level;
level = 101 - level;
while (level < 0 || level >2147483000) {
POS::SetPos(35, 11);
cout << "请输入您选择的难度级别,级别为1-100" ;
POS::SetPos(30, 10);
cin >> level;
}
return level;
}

void Face::drawMyPlane(int x, int y)
{
POS::SetPos(x, y - 1);
cout << "||";
POS::SetPos(x - 2 , y);
cout << "OO||OO";
POS::SetPos(x - 1, y + 1);
cout << "O||O" ;
POS::HideCursor();
}

void Face::drawEmeyPlane(int x, int y)
{
POS::SetPos(x - 1 , y - 1);
cout << "O||O";
POS::SetPos(x-2, y);
cout << "OO||OO";
POS::SetPos(x, y + 1);
cout << "||";
POS::HideCursor();
}

pos.h

#pragma once

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <string>
using namespace std;

typedef struct
{
COORD position[11];
int flag;
}Frame;

class POS
{
public:
//移动光标
static void SetPos(COORD a);
//移动光标
static void SetPos(int i, int j);
//隐藏光标
static void HideCursor();
//把第y行,[x1, x2) 之间的坐标填充为 ch
static void drawRow(int y, int x1, int x2, char ch);
//在a, b 纵坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
static void drawRow(COORD a, COORD b, char ch);
//把第x列,[y1, y2] 之间的坐标填充为 ch
static void drawCol(int x, int y1, int y2, char ch);
//在a, b 横坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
static void drawCol(COORD a, COORD b, char ch);
//左上角坐标、右下角坐标、用row填充行、用col填充列
static void drawFrame(COORD a, COORD b, char row, char col);
//左上角坐标(x1,y1)、右下角坐标(x2,y2)、用row填充行、用col填充列
static void drawFrame(int x1, int y1, int x2, int y2, char row, char col);

static void drawFrame(Frame frame, char row, char col);

static int random(int a, int b);

static COORD random(COORD a, COORD b);

};

pos.cpp

#include "pos.h"
#include <assert.h>

void POS::SetPos(COORD a)// set cursor
{
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(out, a);
}

void POS::SetPos(int i, int j)// set cursor
{
COORD pos = { i, j };
SetPos(pos);
}

void POS::HideCursor() //隐藏光标
{
CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

//把第y行,[x1, x2) 之间的坐标填充为 ch
void POS::drawRow(int y, int x1, int x2, char ch)
{
SetPos(x1, y);
for (int i = 0; i <= (x2 - x1); i++)
cout << ch;
}

//在a, b 纵坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
void POS::drawRow(COORD a, COORD b, char ch)
{
assert(a.Y == b.Y);
drawRow(a.Y, a.X, b.X, ch);
}

//把第x列,[y1, y2] 之间的坐标填充为 ch
void POS::drawCol(int x, int y1, int y2, char ch)
{
assert(y1 <= y2);
for (int y = y1; y <= y2; y++) {
SetPos(x, y);
cout << ch;
}
}

//在a, b 横坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
void POS::drawCol(COORD a, COORD b, char ch)
{
assert(a.X == b.X);
drawCol(a.X, a.Y, b.Y, ch);
}

//左上角坐标、右下角坐标、用row填充行、用col填充列
void POS::drawFrame(COORD a, COORD b, char row, char col)
{
drawRow(a.Y, a.X + 1, b.X - 1, row);
drawRow(b.Y, a.X + 1, b.X - 1, row);
drawCol(a.X, a.Y + 1, b.Y - 1, col);
drawCol(b.X, a.Y + 1, b.Y - 1, col);
}

void POS::drawFrame(int x1, int y1, int x2, int y2, char row, char col)
{
COORD a = { x1, y1 };
COORD b = { x2, y2 };
drawFrame(a, b, row, col);
}

void POS::drawFrame(Frame frame, char row, char col)
{
COORD a = frame.position[0];
COORD b = frame.position[1];
drawFrame(a, b, row, col);
}

//在[a, b)之间产生一个随机整数
int POS::random(int a, int b)
{
int c = (rand() % (a - b)) + a;
return c;
}

//在两个坐标包括的矩形框内随机产生一个坐标
COORD POS::random(COORD a, COORD b)
{
int x = random(a.X, b.X);
int y = random(a.Y, b.Y);
COORD c = { x, y };
return c;
}

Game.h

#pragma once
#include "Face.h"

class Game
{

public:
COORD position[10];
COORD bullet[10];
Frame enemy[8];
int score;
int rank;
int rankf;
string title;
int flag_rank;

Game();

//初始化所有
void initPlane();
void initBullet();
void initEnemy();

//初始化其中一个
//void initThisBullet( COORD );
//void initThisEnemy( Frame );

void planeMove(char);
void bulletMove();
void enemyMove();

bool judgeCoordInFrame(Frame frame, COORD spot);

//填充所有
void drawPlane();
void drawPlaneToNull();
void drawBullet();
void drawBulletToNull();
void drawEnemy();
void drawEnemyToNull();

//填充其中一个
void drawThisBulletToNull(COORD);
void drawThisEnemyToNull(Frame);

void Pause();
void Playing();
void judgePlane();
void judgeEnemy();

void Shoot();

void GameOver();
void printScore();
};

Game.cpp

#include "Game.h"

Game::Game()
{
initPlane();
initBullet();
initEnemy();
score = 0;
rank = 25;
rankf = 0;
flag_rank = 0;
}

void Game::initPlane()
{
COORD centren = { 39, 22 };
position[0].X = position[5].X = position[7].X = position[9].X = centren.X;
position[1].X = centren.X - 2;
position[2].X = position[6].X = centren.X - 1;
position[3].X = position[8].X = centren.X + 1;
position[4].X = centren.X + 2;
for (int i = 0; i <= 4; i++)
position[i].Y = centren.Y;
for (int i = 6; i <= 8; i++)
position[i].Y = centren.Y + 1;
position[5].Y = centren.Y - 1;
position[9].Y = centren.Y - 2;
}

bool Game::judgeCoordInFrame(Frame frame, COORD spot)
{
if (spot.X >= frame.position[0].X)
if (spot.X <= frame.position[1].X)
if (spot.Y >= frame.position[0].Y)
if (spot.Y <= frame.position[0].Y)
return true;
return false;
}
void Game::drawPlane()
{
for (int i = 0; i<9; i++)
{
POS::SetPos(position[i]);
switch (i) {
case 0:cout << "O"; break;
case 1:
case 4:cout << "I"; break;
case 2:
case 3:cout << "-"; break;
case 5:cout << "A"; break;
case 6:
case 8:cout << "V"; break;
case 7:cout << "^"; break;
}
}
}

void Game::drawPlaneToNull()
{
for (int i = 0; i<9; i++)
{
POS::SetPos(position[i]);
cout << " ";
}
}

void Game::initBullet()
{
for (int i = 0; i<10; i++)
bullet[i].Y = 30;
}

void Game::drawBullet()
{
for (int i = 0; i<10; i++)
{
if (bullet[i].Y != 30)
{
POS::SetPos(bullet[i]);
cout << "*";
}
}
}

void Game::drawBulletToNull()
{
for (int i = 0; i<10; i++)
if (bullet[i].Y != 30)
{
COORD pos = { bullet[i].X, bullet[i].Y + 1 };
POS::SetPos(pos);
cout << " ";
}
}


void Game::initEnemy()
{
COORD a = { 1, 1 };
COORD b = { 45, 15 };
for (int i = 0; i<8; i++)
{
enemy[i].position[0] = POS::random(a, b);

enemy[i].position[1].X = enemy[i].position[0].X + 4;
enemy[i].position[1].Y = enemy[i].position[0].Y + 2;

enemy[i].position[2].Y = enemy[i].position[3].Y = enemy[i].position[4].Y = enemy[i].position[0].Y;
for (int j = 5; j < 10; j++)
enemy[i].position[j].Y = enemy[i].position[0].Y + 1;
enemy[i].position[10].Y = enemy[i].position[0].Y + 2;

enemy[i].position[5].X = enemy[i].position[0].X;
enemy[i].position[2].X = enemy[i].position[6].X = enemy[i].position[0].X + 1;
enemy[i].position[3].X = enemy[i].position[7].X = enemy[i].position[10].X = enemy[i].position[0].X + 2;
enemy[i].position[4].X = enemy[i].position[8].X = enemy[i].position[0].X + 3;
enemy[i].position[9].X = enemy[i].position[0].X + 4;
}
}
/*
III
I=X=I
I
*/

void Game::drawEnemy()
{
for (int i = 0; i < 8; i++) {
for (int j = 2; j < 11; j++) {
POS::SetPos(enemy[i].position[j]);
switch (j) {
case 2:
case 3:
case 4:
case 5:
case 9:
case 10:cout << "I"; break;
case 6:
case 8:cout << "="; break;
case 7:cout << "X"; break;
}
}

/*cout << " III " << endl;
POS::SetPos(enemy[i].position[2]);
cout << "I=X=I" << endl;
POS::SetPos(enemy[i].position[3]);
cout << " I ";*/

}
//POS::drawFrame(enemy[i].position[0], enemy[i].position[1], '-', '|');
}

void Game::drawEnemyToNull()
{
for (int i = 0; i<8; i++)
{
for (int j = 2; j < 11; j++) {
POS::SetPos(enemy[i].position[j]);
cout << " ";
}
//POS::drawFrame(enemy[i].position[0], enemy[i].position[1], ' ', ' ');
}
}

void Game::Pause()
{
POS::SetPos(61, 2);
cout << " ";
POS::SetPos(61, 2);
cout << "暂停中...";
char c = _getch();
while (c != 'p')
c = _getch();
POS::SetPos(61, 2);
cout << " ";
}

void Game::planeMove(char x)
{
if (x == 'a')
if (position[1].X != 1)
for (int i = 0; i <= 9; i++)
position[i].X -= 2;

if (x == 's')
if (position[7].Y != 23)
for (int i = 0; i <= 9; i++)
position[i].Y += 1;

if (x == 'd')
if (position[4].X != 47)
for (int i = 0; i <= 9; i++)
position[i].X += 2;

if (x == 'w')
if (position[5].Y != 3)
for (int i = 0; i <= 9; i++)
position[i].Y -= 1;
}

void Game::bulletMove()
{
for (int i = 0; i<10; i++)
{
if (bullet[i].Y != 30)
{
bullet[i].Y -= 1;
if (bullet[i].Y == 1)
{
COORD pos = { bullet[i].X, bullet[i].Y + 1 };
drawThisBulletToNull(pos);
bullet[i].Y = 30;
}

}
}
}

void Game::enemyMove()
{
for (int i = 0; i<8; i++)
{
for (int j = 0; j<11; j++)
enemy[i].position[j].Y++;

if (24 == enemy[i].position[1].Y)
{
COORD a = { 1, 1 };
COORD b = { 45, 3 };
enemy[i].position[0] = POS::random(a, b);
enemy[i].position[1].X = enemy[i].position[0].X + 4;
enemy[i].position[1].Y = enemy[i].position[0].Y + 2;
enemy[i].position[2].Y = enemy[i].position[3].Y = enemy[i].position[4].Y = enemy[i].position[0].Y;
for (int j = 5; j < 10; j++)
enemy[i].position[j].Y = enemy[i].position[0].Y + 1;
enemy[i].position[10].Y = enemy[i].position[0].Y + 2;

enemy[i].position[5].X = enemy[i].position[0].X;
enemy[i].position[2].X = enemy[i].position[6].X = enemy[i].position[0].X + 1;
enemy[i].position[3].X = enemy[i].position[7].X = enemy[i].position[10].X = enemy[i].position[0].X + 2;
enemy[i].position[4].X = enemy[i].position[8].X = enemy[i].position[0].X + 3;
enemy[i].position[9].X = enemy[i].position[0].X + 4;
}
}
}

void Game::judgePlane()
{
for (int i = 0; i < 8; i++)
for (int j = 0; j<9; j++)
if (judgeCoordInFrame(enemy[i], position[j]))
{
POS::SetPos(62, 1);
cout << "坠毁";
POS::drawFrame(enemy[i], '+', '+');
Sleep(1000);
GameOver();
break;
}
}

void Game::drawThisBulletToNull(COORD c)
{
POS::SetPos(c);
cout << " ";
}

void Game::drawThisEnemyToNull(Frame f)
{
for (int j = 2; j < 11; j++) {
POS::SetPos(f.position[j]);
cout << " ";
}
//POS::drawFrame(f, ' ', ' ');
}

void Game::judgeEnemy()
{
for (int i = 0; i < 8; i++)
for (int j = 0; j < 10; j++)
if (judgeCoordInFrame(enemy[i], bullet[j]))
{
score += 5;
drawThisEnemyToNull(enemy[i]);
COORD a = { 1, 1 };
COORD b = { 45, 3 };
enemy[i].position[0] = POS::random(a, b);
enemy[i].position[1].X = enemy[i].position[0].X + 4;
enemy[i].position[1].Y = enemy[i].position[0].Y + 2;
enemy[i].position[2].Y = enemy[i].position[3].Y = enemy[i].position[4].Y = enemy[i].position[0].Y;
for (int j = 5; j < 10; j++)
enemy[i].position[j].Y = enemy[i].position[0].Y + 1;
enemy[i].position[10].Y = enemy[i].position[0].Y + 2;

enemy[i].position[5].X = enemy[i].position[0].X;
enemy[i].position[2].X = enemy[i].position[6].X = enemy[i].position[0].X + 1;
enemy[i].position[3].X = enemy[i].position[7].X = enemy[i].position[10].X = enemy[i].position[0].X + 2;
enemy[i].position[4].X = enemy[i].position[8].X = enemy[i].position[0].X + 3;
enemy[i].position[9].X = enemy[i].position[0].X + 4;
drawThisBulletToNull(bullet[j]);
bullet[j].Y = 30;
}
}

void Game::Shoot()
{
for (int i = 0; i<10; i++)
if (bullet[i].Y == 30)
{
bullet[i].X = position[5].X;
bullet[i].Y = position[5].Y - 1;
break;
}
}

void Game::printScore()
{
if (score == 120 && flag_rank == 0)
{
rank -= 3;
flag_rank = 1;
}

else if (score == 360 && flag_rank == 1)
{
rank -= 5;
flag_rank = 2;
}
else if (score == 480 && flag_rank == 2)
{
rank -= 5;
flag_rank = 3;
}
int x = rank / 5;
POS::SetPos(60, 6);
cout << score;

if (rank != rankf)
{
POS::SetPos(60, 7);
if (x == 5)
title = "初级飞行员";
else if (x == 4)
title = "中级飞行员";
else if (x == 3)
title = "高级飞行员";
else if (x == 2)
title = "王牌飞行员";
cout << title;
}
rankf = rank;
}

void Game::Playing()
{
//HANDLE MFUN;
//MFUN= CreateThread(NULL, 0, MusicFun, NULL, 0, NULL);

drawEnemy();
drawPlane();

int flag_bullet = 0;
int flag_enemy = 0;

while (1)
{
Sleep(8);
if (_kbhit())
{
char x = _getch();
if ('a' == x || 's' == x || 'd' == x || 'w' == x)
{
drawPlaneToNull();
planeMove(x);
drawPlane();
judgePlane();
}
else if ('p' == x)
Pause();
else if ('k' == x)
Shoot();
else if ('e' == x)
{
//CloseHandle(MFUN);
GameOver();
break;
}

}
/* 处理子弹 */
if (0 == flag_bullet)
{
bulletMove();
drawBulletToNull();
drawBullet();
judgeEnemy();
}
flag_bullet++;
if (5 == flag_bullet)
flag_bullet = 0;

/* 处理敌人 */
if (0 == flag_enemy)
{
drawEnemyToNull();
enemyMove();
drawEnemy();
judgePlane();
}
flag_enemy++;
if (flag_enemy >= rank)
flag_enemy = 0;

/* 输出得分 */
printScore();
}
}

void Game::GameOver()
{
system("cls");
COORD p1 = { 28,9 };
COORD p2 = { 53,15 };
POS::drawFrame(p1, p2, '=', '|');
POS::SetPos(36, 12);
string str = "Game Over!";
for (int i = 0; i<str.size(); i++)
{
Sleep(80);
cout << str[i];
}
Sleep(1000);
system("cls");
POS::drawFrame(p1, p2, '=', '|');
POS::SetPos(31, 11);
cout << "击落敌机:" << score / 5 << " 架";
POS::SetPos(31, 12);
cout << "得  分:" << score;
POS::SetPos(31, 13);
cout << "获得称号:" << title;
POS::SetPos(30, 16);
Sleep(1000);
cout << "继续? 是(y)| 否(n)";
as:
char x = _getch();
if (x == 'n')
exit(0);
else if (x == 'y')
{
system("cls");
Game game;
int a = Face::drawWelcome();
game.rank = a;
system("cls");
Face::drawPlaying();
game.Playing();
}
else goto as;
}

main.cpp

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <string>
#include "Game.h"
using namespace std;

int main() {
//游戏准备
srand((int)time(0)); //随机种子
POS::HideCursor(); //隐藏光标

Game game;
int a = Face::drawWelcome();
game.rank = a;
system("cls");
Face::drawPlaying();
game.Playing();
return 0;
}

课程设计二

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QKeyEvent>
#include <QEvent>
#include <QLabel>
#include <QPainter>
#include <QKeyEvent>
#include <QDebug>
#include <QSize>
#include <QTimer>
#include <QLabel>
#include <QMovie>
#include <QDebug>

#define NUM_enemy 6
#define NUM_buttle 100
#define Value_buttle 30

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
Q_OBJECT

public:
explicit Dialog(QWidget *parent = 0);
int score;
int numhit;
int Value_enemy;
//QMovie boom;
//QLabel bomb;
QLabel boompic;
QString boomsheet;

QLabel* buttle[100];
QLabel* enemy[6];
//String title;
void initPlane();
void initLabel();
void initEnemy();
void initButtle();
void restart();
int timeid;
int boomid;
//int gameoverid;

void judgeplane();
void judgebullet();
void shoot();
void pause();
void gameover();
~Dialog();

private slots:
void keyPressEvent(QKeyEvent *k);
void timerEvent(QTimerEvent *event);
private:
Ui::Dialog *ui;
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"
#include <time.h>

Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
srand((int)time(0)); //随机种子
ui->setupUi(this);
restart();
}
//在[a, b)之间产生一个随机整数
int random(int a, int b)
{
int c = (rand() % (a - b)) + a;
return c;
}
Dialog::~Dialog()
{
delete ui;
}

void Dialog::restart(){
initLabel();//初始化右侧栏目
initPlane();//初始化我方飞机位置
initEnemy();//初始化敌方飞机位置
initButtle();//初始化子弹
ui->gameover->hide();
timeid = startTimer(50);
score = 0;
numhit = 0;
ui->numhit->setText(QString::number(numhit));
ui->score->setText(QString::number(score));
boompic.setParent(ui->frame_2);
boompic.clear();
boompic.hide();
}

void Dialog::initLabel(){
ui->label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->numhit->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->score->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->label_4->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->honor->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->label_6->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->label_7->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
}

void Dialog::initPlane(){
ui->myplane->move(300,530);
}
void Dialog::initEnemy(){
enemy[0]=ui->enemy_1;
enemy[1]=ui->enemy_2;
enemy[2]=ui->enemy_3;
enemy[3]=ui->enemy_4;
enemy[4]=ui->enemy_5;
enemy[5]=ui->enemy_6;
for(int i=0;i<6;i++)
enemy[i]->move(random(0,630),random(-200,-100));
}

void Dialog::initButtle(){//子弹位置是战机位置x+60,y-90.y==-70的时候就可以消失了
for(int i=0;i<NUM_buttle;i++){
buttle[i]=new QLabel("");
buttle[i]->setParent(ui->frame_2);
buttle[i]->hide();
buttle[i]->resize(QSize(20,100));
QString a = "QLabel{border-image: url(:/bullets.png);background-color: transparent;}";
buttle[i]->setStyleSheet(a);

}
}


void Dialog::judgeplane(){
int rc1_x = ui->myplane->x()+20;
int rc1_y = ui->myplane->y()+10;
int rc1_width = ui->myplane->size().width()-40;
int rc1_height = ui->myplane->size().height()-20;
for(int i=0;i<NUM_enemy;i++){
int rc2_x = enemy[i]->x();
int rc2_y = enemy[i]->y();
int rc2_width = enemy[i]->size().width();
int rc2_height = enemy[i]->size().height();

if (rc1_x + rc1_width > rc2_x &&
rc2_x + rc2_width > rc1_x &&
rc1_y + rc1_height > rc2_y &&
rc2_y + rc2_height > rc1_y
){
/*int boom_x = ui->myplane->x();
int boom_y = ui->myplane->y();
QSize boom_p = ui->myplane->size();
boomsheet = "QLabel{border-image: url(:/bomb1.png);background-color: transparent;}";
boompic.setStyleSheet(boomsheet);
boompic.move(boom_x,boom_y);
boompic.resize(boom_p);
boompic.show();
boomid=startTimer(100);
gameoverid=startTimer(800);*/
gameover();
}
}
}

void Dialog::judgebullet(){
for(int i=0;i<NUM_buttle;i++){
if(!buttle[i]->isHidden()){
int rc1_x = buttle[i]->x();
int rc1_y = buttle[i]->y();
int rc1_width = buttle[i]->size().width();
int rc1_height = buttle[i]->size().height();

for(int j=0;j<NUM_enemy;j++){
int rc2_x = enemy[j]->x();
int rc2_y = enemy[j]->y();
int rc2_width = enemy[j]->size().width();
int rc2_height = enemy[j]->size().height();

if (rc1_x + rc1_width > rc2_x &&
rc2_x + rc2_width > rc1_x &&
rc1_y + rc1_height > rc2_y &&
rc2_y + rc2_height > rc1_y
){//命中敌机
buttle[i]->hide();
int boom_x = enemy[j]->x();
int boom_y = enemy[j]->y();
QSize boom_p = enemy[j]->size();
boomsheet = "QLabel{border-image: url(:/bomb1.png);background-color: transparent;}";
boompic.setStyleSheet(boomsheet);
boompic.move(boom_x,boom_y);
boompic.resize(boom_p);
boompic.show();
boomid=startTimer(100);

enemy[j]->move(random(0,630),random(-200,-100));
score += 10;
numhit++;
ui->score->setText(QString::number(score));
ui->numhit->setText(QString::number(numhit));


}
}
}
}
}

void Dialog::shoot(){
int i;
for(i=0;i<NUM_buttle;i++){
if(buttle[i]->isHidden())
break;
}
if(i<NUM_buttle){
buttle[i]->move(ui->myplane->x()+60,ui->myplane->y());
buttle[i]->show();
}
}

void Dialog::pause(){
killTimer(timeid);
}

void Dialog::gameover(){
pause();
ui->gameover->show();
}

void Dialog::timerEvent(QTimerEvent *event){
if(event->timerId() == timeid){
// 子弹移动
for(int i=0;i<NUM_buttle;i++){
if(!buttle[i]->isHidden()){
if(buttle[i]->y() < -100)
buttle[i]->hide();
else
buttle[i]->move(buttle[i]->x(),buttle[i]->y()-Value_buttle);
}
}
judgebullet();
judgeplane();
for(int j=0;j<NUM_enemy;j++){
if(!enemy[j]->isHidden()){
if(enemy[j]->y()>660){
enemy[j]->move(random(0,630),random(-200,-100));
}
else
enemy[j]->move(enemy[j]->x(),enemy[j]->y()+Value_enemy);
}
}
if(score > 200 && score < 1000)
ui->honor->setText(QString("中级飞行员"));
else if(score > 1000)
ui->honor->setText(QString("高级飞行员"));
}
else if(event->timerId() == boomid){
//bomb.hide();
switch(boomsheet[31].toLatin1()){
case '1':boomsheet[31]='2';boompic.setStyleSheet(boomsheet);boompic.update();break;
case '2':boomsheet[31]='3';boompic.setStyleSheet(boomsheet);boompic.update();break;
case '3':boomsheet[31]='4';boompic.setStyleSheet(boomsheet);boompic.update();break;
case '4':boomsheet[31]='5';boompic.setStyleSheet(boomsheet);boompic.update();break;
case '5':boomsheet[31]='6';boompic.setStyleSheet(boomsheet);boompic.update();break;
case '6':boomsheet[31]='7';boompic.setStyleSheet(boomsheet);boompic.update();break;
case '7':boomsheet[31]='1';boompic.setStyleSheet(boomsheet);killTimer(boomid);boompic.hide();break;
default:qDebug()<<boomsheet[31].toLatin1();
}
}

}

void Dialog::keyPressEvent(QKeyEvent *k)
{
switch(k->key()){
case Qt::Key_W:
if(ui->myplane->y()<=0)break;
ui->myplane->move(ui->myplane->x(),ui->myplane->y()-10);judgeplane();break;
case Qt::Key_S:
if(ui->myplane->y()>=640)break;
ui->myplane->move(ui->myplane->x(),ui->myplane->y()+10);judgeplane();break;
case Qt::Key_A:
if(ui->myplane->x()<=0)break;
ui->myplane->move(ui->myplane->x()-10,ui->myplane->y());judgeplane();break;
case Qt::Key_D:
if(ui->myplane->x()>=740)break;
ui->myplane->move(ui->myplane->x()+10,ui->myplane->y());judgeplane();break;
/*case (Qt::Key_W | Qt::Key_A):ui->myplane->move(ui->myplane->x()-10,ui->myplane->y()-10);judgeplane();break;
case (Qt::Key_W | Qt::Key_D):ui->myplane->move(ui->myplane->x()+10,ui->myplane->y()-10);judgeplane();break;
case (Qt::Key_S | Qt::Key_A):ui->myplane->move(ui->myplane->x()-10,ui->myplane->y()+10);judgeplane();break;
case (Qt::Key_S | Qt::Key_D):ui->myplane->move(ui->myplane->x()+10,ui->myplane->y()+10);judgeplane();break;*/
case Qt::Key_K:shoot();break;
case Qt::Key_P:pause();break;
case Qt::Key_O:timeid = startTimer(50);break;
case Qt::Key_E:gameover();this->close();break;
case Qt::Key_R:restart();break;
}

}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "dialog.h"
#include <QLabel>
#include <QMovie>



namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Dialog gameui;

private slots:
void on_pushButton_clicked();

void on_pushButton_2_clicked();

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
gameui.hide();

}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_pushButton_clicked()
{
this->hide();
gameui.Value_enemy = 5;
gameui.restart();
gameui.show();
}

void MainWindow::on_pushButton_2_clicked()
{
this->hide();
gameui.Value_enemy = 10;
gameui.restart();
gameui.show();
}

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}