目录
最近系统学习了Qt的程序界面开发,所以用Qt尝试写了一个简单的魔塔小游戏。
下述括号内内容暂未编写
一.游戏大致内容
1.玩家角色
玩家角色拥有:角色名字,血量,攻击,防御,金钱,钥匙,剑,盾,(技能,经验,等级)
通过玩家角色保存层数
2.怪物
怪物拥有:怪物名字,血量,攻击,防御,金钱,(技能,经验,等级)
怪物名字不方便在代码中使用,所以给怪物添加一个“类型”变量
3.可触发的物品
可与玩家互动的物品
如:血瓶,(蓝瓶),钥匙,宝石,剑,盾,门等
4.不可触发的物品
地面,墙等
5.地图
初始地图与当前地图
6.(玩家与怪物的技能)
(技能拥有等级,加成,蓝耗等属性)
二.实现逻辑
除去暂时不想写的内容,将玩家角色写为一个类,怪物一个类,地图一个类,主界面一个类
玩家的活动可以写在玩家类中,也可以写在主界面类中——更方便刷新主界面;玩家应有移动,战斗等事件;主界面应有初始化,刷新界面,接收键盘按键事件等功能
使用Qt中的QLable控件装载地图的各种图标,用QPainter绘制游戏背景,用QMediaPlayer播放游戏背景音乐
地图用三维数组存储,每一张地图都是一个二维数组,则会将地图分割成网格状,通过多个QLable控件拼接成整张地图界面
三.具体实现
所有类的成员变量都写成了公有成员,方便在类外部通过该类对象使用这些变量
1.角色类声明
class Hero
{
public:
Hero(QString);
~Hero();
int blood; //血量
int attack; //攻击力
int defense; //防御力
int money; //金钱
int floor; //楼层
int b_key; //蓝钥匙
int y_key; //黄钥匙
bool sword; //持剑标志
bool shield; //持盾标志
QString name;
};
2.怪物类声明
class Monster
{
public:
Monster(int);
~Monster();
QString name;
int blood; //生命值
int attack; //攻击力
int defense; //防御力
int money; //金钱
int type; //类型 8-蓝史莱姆 9-黄史莱姆 10-蝙蝠 11-骷髅 12-法师
};
3.地图类声明
三维数组若声明未赋值则后续不方便赋值,需使用三重for循环赋值,不方便脑补绘制地图,所以在类中声明时就为其赋值
class Map
{
public:
Map();
//0-墙1-地板 2-蓝门 3-黄门 4-蓝钥匙 5-黄钥匙 6-小血瓶 7-大血瓶
//8-蓝史雷姆 9-黄史雷姆 10-蝙蝠 11-骷髅 12-法师 13-红宝石 14-蓝宝石
//15-英雄 16-上楼 17-下楼 18-剑 19-盾
/* //空地图,用于复制
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
*/
int map[TOWER_LAYER][ONCE_WIDTH][ONCE_HEIGHT]={
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,16,5,1,1,1,1,1,1,1,1,14,0},
{0,5,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,18,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,6,1,1,1,1,1,1,1,1,1,15,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,16,1,9,8,8,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,1,0},
{0,5,1,1,3,1,0,1,5,1,0,1,0},
{0,1,11,1,0,1,0,14,6,1,0,1,0},
{0,0,3,0,0,1,0,0,0,3,0,1,0},
{0,5,1,1,0,1,3,10,11,10,0,1,0},
{0,1,11,1,0,1,0,0,0,0,0,1,0},
{0,0,3,0,0,1,1,1,1,1,1,1,0},
{0,1,1,1,0,0,3,0,0,0,3,0,0},
{0,6,1,5,0,1,1,1,0,1,10,1,0},
{0,6,13,5,0,17,15,1,0,9,7,8,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,5,14,0,5,7,5,0,1,0,1,6,0},
{0,1,6,0,7,5,7,0,1,3,10,1,0},
{0,12,1,0,5,4,5,0,1,0,0,0,0},
{0,3,0,0,0,1,0,0,1,0,1,12,0},
{0,1,1,10,1,1,1,9,1,1,1,1,0},
{0,3,0,0,1,1,1,0,1,0,0,0,0},
{0,11,1,0,0,1,0,0,1,0,1,6,0},
{0,1,5,0,1,1,1,0,1,3,12,5,0},
{0,6,6,0,1,1,1,0,1,0,0,0,0},
{0,0,0,0,0,1,0,0,9,0,1,1,0},
{0,17,15,1,1,1,1,0,1,3,1,16,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,5,1,0,1,1,1,0,1,12,1,0},
{0,6,13,4,0,1,12,1,0,5,1,7,0},
{0,1,1,1,0,1,1,1,0,1,11,1,0},
{0,0,3,0,0,0,2,0,0,0,3,0,0},
{0,1,12,1,3,1,1,1,1,1,1,1,0},
{0,1,1,1,0,0,0,0,0,0,0,0,0},
{0,9,1,8,1,1,1,1,1,1,1,1,0},
{0,3,0,0,3,0,0,0,3,0,0,3,0},
{0,1,0,9,10,5,0,1,12,1,0,1,0},
{0,1,0,5,1,5,0,9,6,9,0,15,0},
{0,16,0,8,8,5,0,1,9,8,0,17,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,17,1,2,1,1,1,1,1,1,1,1,0},
{0,15,1,0,1,1,12,1,12,1,1,1,0},
{0,1,0,0,0,0,0,1,0,0,0,0,0},
{0,1,0,5,5,0,1,1,1,0,5,12,0},
{0,1,0,5,5,3,1,1,1,3,1,5,0},
{0,1,0,0,0,0,1,1,1,0,0,0,0},
{0,1,0,12,11,0,1,1,1,0,5,7,0},
{0,1,0,1,1,3,1,1,1,3,1,5,0},
{0,1,0,0,0,0,1,1,1,0,0,0,0},
{0,1,0,7,7,0,1,1,1,0,12,19,0},
{0,16,0,7,14,3,1,1,1,3,12,12,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,16,0,1,10,3,1,0,1,1,3,1,0},
{0,1,0,1,1,0,5,0,11,12,0,2,0},
{0,1,3,11,1,0,1,0,5,5,0,1,0},
{0,0,0,0,3,0,10,0,5,5,0,1,0},
{0,5,5,12,12,0,1,0,0,0,0,1,0},
{0,5,1,1,11,0,1,12,1,1,1,1,0},
{0,0,11,0,0,0,1,0,0,0,0,12,0},
{0,1,12,1,1,0,10,0,1,1,1,1,0},
{0,13,5,7,5,0,1,0,1,0,0,0,0},
{0,0,0,0,0,0,5,0,1,0,7,14,0},
{0,17,15,1,1,1,1,0,1,3,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,17,15,7,7,7,7,7,7,7,7,7,0},
{0,1,1,14,14,14,14,14,14,14,14,14,0},
{0,1,1,13,13,13,13,13,13,13,13,13,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,16,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,17,15,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,12,12,12,12,12,0},
{0,1,1,1,1,1,1,12,12,12,12,12,0},
{0,1,1,1,1,1,1,12,12,12,12,12,0},
{0,1,1,1,1,1,1,12,12,12,12,12,0},
{0,1,1,1,1,1,1,12,12,12,12,12,0},
{0,1,1,1,1,1,1,12,12,12,12,12,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
}
};
};
4.主界面声明
class Widget : public QWidget
{
Q_OBJECT
public slots:
void startGame(); //开始按钮所实现的自定义槽函数
public:
Widget(QWidget *parent = 0);
~Widget();
void keyPressEvent(QKeyEvent *event); //键盘事件重写,上下左右与WASD键的改写
void paintEvent(QPaintEvent *event); //绘图事件重写,素材背景为白板,需要绘制背景
void initMap(); //初始化游戏地图函数
void updateMap(int type,int preValue=0); //刷新游戏地图函数
void heroMove(int type,int preValue); //角色移动判断函数
void heroCombat(int preValue); //角色战斗判断函数
void showHeroInfo(); //显示角色信息函数
private:
QPushButton *start_bt; //开始按钮
bool combate_signal; //角色战斗标志
bool restart_signal; //死亡重开标志
bool start_background_signal; //更新背景图标志
QMediaPlayer *bgm; //播放背景音乐
QMediaPlaylist *bgmlist; //背景音乐列表,用于循环播放
QLabel *mapLabel[13][13]; //当前地图
QLabel *infoLabel; //角色信息背景
QLabel *nameLabel; //角色名字
QLabel *moneyValueLabel; //金币
QLabel *floorValueLabel; //楼层
QLabel *bloodLabel; //生命值
QLabel *attackLabel; //攻击力
QLabel *defenseLabel; //防御力
QLabel *bKeyLabel; //蓝钥匙
QLabel *yKeyLabel; //黄钥匙
Map *dynamic_map=new Map; //当前游戏的地图
Map *static_map=new Map; //不会去更改的地图,其实也可以用Map::map来调用
Hero *hero; //声明角色
int heroX; //角色的模拟X坐标
int heroY; //角色的模拟Y坐标
//声明定义怪物
Monster *blueSlime=new Monster(8);
Monster *yellowSlime=new Monster(9);
Monster *smallBat=new Monster(10);
Monster *skeletonKnight=new Monster(11);
Monster *exorcist=new Monster(12);
};
5.玩家角色的构造
Hero::Hero(QString name_):name(name_)
{
//根据传入角色名生成指定角色
if(name.compare("英雄")){
blood=200;
attack=20;
defense=15;
}
else if(name.compare("勇者")){
blood=100;
attack=16;
defense=10;
}
else if(name.compare("村民")){
blood=60;
attack=10;
defense=8;
}
else {
blood=40;
attack=10;
defense=5;
}
money=0;
floor=0;
b_key=0;
y_key=0;
}
6.怪物的构造
Monster::Monster(int type){
this->type=type;
//根据传入类型生成指定小怪
switch (type){
case 8:
blood=30;
attack=12;
defense=5;
money=2;
name="黄史莱姆";
break;
case 9:
blood=50;
attack=13;
defense=5;
money=3;
name="蓝史莱姆";
break;
case 10:
blood=50;
attack=15;
defense=8;
money=5;
name="蝙蝠";
break;
case 11:
blood=100;
attack=18;
defense=12;
money=20;
name="骷髅";
break;
case 12:
blood=200;
attack=26;
defense=10;
money=30;
name="法师";
break;
default:
break;
}
}
7.地图的构造
因为地图数组在声明时就赋值了,所以不需要重写地图的构造函数
8.主界面构造
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->grabKeyboard();//设置接收键盘事件
this->setFixedSize((ONCE_WIDTH+1.5)*60,ONCE_HEIGHT*60);
//背景音乐
bgm=new QMediaPlayer();
bgmlist=new QMediaPlaylist();//用QMediaPlaylist装入背景音乐,使其能循环播放
bgmlist->addMedia(QUrl("qrc:/bgm/morning.mp3"));
bgmlist->setPlaybackMode(QMediaPlaylist::Loop);
bgm->setPlaylist(bgmlist);
bgm->setVolume(30);//设置音量大小
bgm->play();
//开始按钮
start_bt=new QPushButton("start game");
start_bt->setFixedSize(140,50);
start_bt->setFont(QFont("KaiTi",16));
start_bt->setStyleSheet("QPushButton{ color:rgb(255,255,255);}"
"QPushButton{ selection-color:rgb(181,181,181);}"
"QPushButton{ border-radius:18px;}"
"QPushButton{ background-color:rgb(0,128,255);}");
start_bt->move(this->width()/2-70,this->height()/2-25);
start_bt->setParent(this);
//初始化各个标志
restart_signal=false;
combate_signal=false;
start_background_signal=false;
//定义角色并初始化其内容
hero=new Hero("英雄");
heroX=0;
heroY=0;
hero->sword=false;
hero->shield=false;
//for循环初始化地图lable
for(int i=0;i<ONCE_WIDTH;i++){
for(int j=0;j<ONCE_HEIGHT;j++){
mapLabel[i][j]=new QLabel(this);
mapLabel[i][j]->setFixedSize(60,60);
}
}
connect(start_bt,SIGNAL(clicked(bool)),this,SLOT(startGame()));
}
9.开始按钮的槽函数与绘图事件
//开始按钮点击后隐藏按钮,跟新地图,立即刷新绘图事件,显示角色信息
void Widget::startGame(){
start_background_signal=true;
start_bt->hide();
repaint();
initMap();
showHeroInfo();
}
//绘图事件,绘制窗口背景图
void Widget::paintEvent(QPaintEvent *event){
QPainter p(this);
event->accept();
//进入游戏后背景改为全游戏地面背景
if(start_background_signal==true){
for(int i=0;i<ONCE_HEIGHT;i++){
for(int j=0;j<ONCE_WIDTH+1;j++){
p.drawPixmap(j*60,i*60,60,60,QPixmap(":/image/1.png"));
}
}
}
//未进入游戏设置开始背景
else{
p.drawPixmap(0,0,60*(ONCE_WIDTH+1.5),60*ONCE_HEIGHT,QPixmap(":/image/back.jpeg"));
}
}
10.键盘事件处理
void Widget::keyPressEvent(QKeyEvent *event){
if(!combate_signal){
int type=4; //记录移动类型(0-上 1-下 2-左 3-右)
int preValue=0; //记录走到的位置有什么东西
switch (event->key()){
case Qt::Key_Up:
case Qt::Key_W:
type=0;
preValue=dynamic_map->map[hero->floor][heroX-1][heroY];
heroMove(type,preValue);
break;
case Qt::Key_Down:
case Qt::Key_S:
type=1;
preValue=dynamic_map->map[hero->floor][heroX+1][heroY];
heroMove(type,preValue);
break;
case Qt::Key_Left:
case Qt::Key_A:
type=2;
preValue=dynamic_map->map[hero->floor][heroX][heroY-1];
heroMove(type,preValue);
break;
case Qt::Key_Right:
case Qt::Key_D:
type = 3;
preValue=dynamic_map->map[hero->floor][heroX][heroY+1];
heroMove(type,preValue);
break;
default:
break;
}
showHeroInfo();//刷新角色信息的显示
}
}
11.初始化地图界面
void Widget::initMap(){
if(restart_signal){
//将不变的地图赋予可变地图
for(int k=0;k<TOWER_LAYER;k++){
for(int i=0;i<ONCE_WIDTH;i++){
for(int j=0;j<ONCE_HEIGHT;j++){
dynamic_map->map[k][i][j]=static_map->map[k][i][j];
}
}
}
//判断角色死亡,是否重新开始。
restart_signal=false;
}
//绘制当前地图
for(int i=0;i<ONCE_HEIGHT;i++){
for(int j=0;j<ONCE_WIDTH;j++){
//每次更新一层,需要刷新当前层的图片
mapLabel[i][j]->clear();
mapLabel[i][j]->move(j*60,i*60);
mapLabel[i][j]->setPixmap(QPixmap(tr(":/image/%1.png").arg(dynamic_map->map[hero->floor][i][j])));
mapLabel[i][j]->setScaledContents(true);
mapLabel[i][j]->show();
//检索角色位置
if(dynamic_map->map[hero->floor][i][j]==15){
heroX=i;
heroY=j;
}
}
}
//计分板背景
infoLabel=new QLabel(this);
infoLabel->setFixedSize(60*1.5,ONCE_HEIGHT*60);
infoLabel->setPixmap(QPixmap(tr(":/image/20.jpeg")));
infoLabel->setScaledContents(true);
infoLabel->move(ONCE_WIDTH*60,0);
infoLabel->show();
//设置字体
QPalette palette;
palette.setColor(QPalette::WindowText,Qt::black);
QFont font;
font.setPointSize(12);
font.setBold(true);
//角色名字
nameLabel=new QLabel(this);
nameLabel->setFixedSize(60*1.5,50);
nameLabel->move(ONCE_WIDTH*60,0);
nameLabel->setPalette(palette);
nameLabel->setFont(font);
nameLabel->show();
//金币显示
moneyValueLabel=new QLabel(this);
moneyValueLabel->setFixedSize(60*1.5,50);
moneyValueLabel->move(ONCE_WIDTH*60,60*1.5);
moneyValueLabel->setPalette(palette);
moneyValueLabel->setFont(font);
moneyValueLabel->show();
//楼层显示
floorValueLabel=new QLabel(this);
floorValueLabel->setFixedSize(60*1.5,50);
floorValueLabel->move(ONCE_WIDTH*60,60*3);
floorValueLabel->setPalette(palette);
floorValueLabel->setFont(font);
floorValueLabel->show();
//生命值
bloodLabel=new QLabel(this);
bloodLabel->setFixedSize(60*1.5,50);
bloodLabel->move(ONCE_WIDTH*60,60*4.5);
bloodLabel->setPalette(palette);
bloodLabel->setFont(font);
bloodLabel->show();
//攻击力
attackLabel=new QLabel(this);
attackLabel->setFixedSize(60*1.5,50);
attackLabel->move(ONCE_WIDTH*60,60*6);
attackLabel->setPalette(palette);
attackLabel->setFont(font);
attackLabel->show();
//防御力
defenseLabel=new QLabel(this);
defenseLabel->setFixedSize(60*1.5,50);
defenseLabel->move(ONCE_WIDTH*60,60*7.5);
defenseLabel->setPalette(palette);
defenseLabel->setFont(font);
defenseLabel->show();
//黄钥匙
yKeyLabel=new QLabel(this);
yKeyLabel->setFixedSize(60*1.5,50);
yKeyLabel->move(ONCE_WIDTH*60,60*9);
yKeyLabel->setPalette(palette);
yKeyLabel->setFont(font);
yKeyLabel->show();
//蓝钥匙
bKeyLabel=new QLabel(this);
bKeyLabel->setFixedSize(60*1.5,50);
bKeyLabel->move(ONCE_WIDTH*60,60*10.5);
bKeyLabel->setPalette(palette);
bKeyLabel->setFont(font);
bKeyLabel->show();
}
12.刷新地图界面
void Widget::updateMap(int type,int preValue){
dynamic_map->map[hero->floor][heroX][heroY]=1;//先前角色所在地置为地面
mapLabel[heroX][heroY]->setPixmap(QPixmap(tr(":/image/%1.png").arg(dynamic_map->map[hero->floor][heroX][heroY])));
switch(type){
case 0:
heroX-=1;
break;
case 1:
heroX+=1;
break;
case 2:
heroY-=1;
break;
case 3:
heroY+=1;
break;
default:
break;
}
//角色移动后位置显示角色
dynamic_map->map[hero->floor][heroX][heroY]=15;
mapLabel[heroX][heroY]->setPixmap(QPixmap(tr(":/image/15.png")));
//攻击怪物,实现图像闪烁
if(preValue==8||preValue==9||preValue==10||preValue==11||preValue==12){
//战斗中,记录战斗状态
combate_signal=true;
//定时器显示怪物图片
QTimer *timer1=new QTimer(this);
connect(timer1,&QTimer::timeout,this,[=](){
mapLabel[heroX][heroY]->setPixmap(QPixmap(tr(":/image/%1.png").arg(preValue)));
});
//定时器显示角色图片
QTimer *timer2=new QTimer(this);
connect(timer2,&QTimer::timeout,this,[=](){
mapLabel[heroX][heroY]->setPixmap(QPixmap(tr(":/image/15.png")));
});
timer1->start(100);
QThread::msleep(50);//线程实现短暂休眠
timer2->start(100);
//500毫秒定时器,定时器结束,闪烁结束
QTimer *timer=new QTimer(this);
connect(timer,&QTimer::timeout,this,[=](){
timer1->stop();
timer2->stop();
timer->stop();
combate_signal=false;
//如果角色战斗失败,则显示怪物图片
if(hero->blood==0){
mapLabel[heroX][heroY]->setPixmap(QPixmap(tr(":/image/%1.png").arg(preValue)));
}
//英雄胜利,则显示角色图片
else{
dynamic_map->map[hero->floor][heroX][heroY]=15;
mapLabel[heroX][heroY]->setPixmap(QPixmap(tr(":/image/15.png")));
}
});
timer->start(500);
}
}
13.角色移动处理
void Widget::heroMove(int type,int preValue){
if(hero->sword){
hero->attack+=12;
hero->sword=false;
}
if(hero->shield){
hero->defense+=8;
hero->shield=false;
}
if(preValue==0){//墙
return;
}
else if(preValue==1){//空地
updateMap(type);
}
else if(preValue==3&&hero->y_key>0){//黄门
updateMap(type);
hero->y_key--;
}
else if(preValue==5){//黄钥匙
updateMap(type);
hero->y_key++;
}
else if(preValue==2&&hero->b_key>0){//蓝门
updateMap(type);
hero->b_key--;
}
else if(preValue==4){//蓝钥匙
updateMap(type);
hero->b_key++;
}
else if(preValue==6){//小血瓶
updateMap(type);
hero->blood+=30;
}
else if(preValue==7){//大血瓶
updateMap(type);
hero->blood+=80;
}
else if(preValue==13){//红宝石
updateMap(type);
hero->attack+=3;
}
else if(preValue==14){//蓝宝石
updateMap(type);
hero->defense+=2;
}
else if(preValue==16){//上楼
hero->floor+=1;
initMap();
}
else if(preValue==17){//下楼
hero->floor-=1;
initMap();
}
else if(preValue==18){//剑
updateMap(type);
hero->sword=true;
}
else if(preValue==19){//盾
updateMap(type);
hero->shield=true;
}
else if(preValue==8||preValue==9||preValue==10||preValue==11||preValue==12){//怪物
heroCombat(preValue);
updateMap(type,preValue);
showHeroInfo();
// 碰见怪物,攻击结束之后判断血量
if(hero->blood==0){
int select=QMessageBox::information(this,tr("游戏结束"),tr("是否重新开始"),QMessageBox::Yes|QMessageBox::No);
if(select==QMessageBox::Yes){
//重新开始
hero=new Hero("英雄");
restart_signal=true;
initMap();
}
else{
this->close();
}
}
}
}
14.运算战斗结果
void Widget::heroCombat(int preValue){
int change_blood; //战斗后减少的血量
int monster_blood; //当前怪物血量
int hero_atk_def; //角色与怪物的攻防差
int monster_atk_def; //怪物与角色的攻防余数
switch (preValue){
case 8:
monster_blood=blueSlime->blood;
hero_atk_def=hero->attack-blueSlime->defense;
monster_atk_def=blueSlime->attack-hero->defense;
hero->money+=blueSlime->money;
break;
case 9:
monster_blood=yellowSlime->blood;
hero_atk_def=hero->attack-yellowSlime->defense;
monster_atk_def=yellowSlime->attack-hero->defense;
hero->money+=yellowSlime->money;
break;
case 10:
monster_blood=smallBat->blood;
hero_atk_def=hero->attack-smallBat->defense;
monster_atk_def=smallBat->attack-hero->defense;
hero->money+=smallBat->money;
break;
case 11:
monster_blood=skeletonKnight->blood;
hero_atk_def=hero->attack-skeletonKnight->defense;
monster_atk_def=skeletonKnight->attack-hero->defense;
hero->money+=skeletonKnight->money;
break;
case 12:
monster_blood=exorcist->blood;
hero_atk_def=hero->attack-exorcist->defense;
monster_atk_def=exorcist->attack-hero->defense;
hero->money+=exorcist->money;
break;
default:
break;
}
//角色防御高于怪物攻击
if(monster_atk_def<=1){
monster_atk_def=1;
}
//角色防御低于怪物攻击过多
else if(monster_atk_def>10){
monster_atk_def=10;
}
//角色攻击低于怪物防御
if(hero_atk_def<0){
change_blood=hero->blood;
}
else{
//角色攻击高于怪物防御过多
if(hero_atk_def>monster_blood){
hero_atk_def=monster_blood;
}
change_blood=(monster_blood/hero_atk_def)*monster_atk_def;
}
//将要改变的血量高于原始血量
if(change_blood>hero->blood){
change_blood=hero->blood;
}
hero->blood-=change_blood;
}
15.边栏角色信息
void Widget::showHeroInfo(){
QString text;
//角色名字
text.append("角色名字\n");
text.append(hero->name);
nameLabel->setText(text);
nameLabel->setAlignment(Qt::AlignCenter);//居中显示
text.clear();//用完清空,方便下次使用
//金币
text.append("金币\n");
text.append(QString::number(hero->money));
moneyValueLabel->setText(text);
moneyValueLabel->setAlignment(Qt::AlignCenter);
text.clear();
//楼层
text.append("楼层\n");
text.append(QString::number(hero->floor));
floorValueLabel->setText(text);
floorValueLabel->setAlignment(Qt::AlignCenter);
text.clear();
//生命值
text.append("生命值\n");
text.append(QString::number(hero->blood));
bloodLabel->setText(text);
bloodLabel->setAlignment(Qt::AlignCenter);
text.clear();
//攻击力
text.append("攻击力\n");
text.append(QString::number(hero->attack));
attackLabel->setText(text);
attackLabel->setAlignment(Qt::AlignCenter);
text.clear();
//防御力
text.append("防御力\n");
text.append(QString::number(hero->defense));
defenseLabel->setText(text);
defenseLabel->setAlignment(Qt::AlignCenter);
text.clear();
//蓝钥匙
text.append("蓝钥匙\n");
text.append(QString::number(hero->b_key));
bKeyLabel->setText(text);
bKeyLabel->setAlignment(Qt::AlignCenter);
text.clear();
//黄钥匙
text.append("黄钥匙\n");
text.append(QString::number(hero->y_key));
yKeyLabel->setText(text);
yKeyLabel->setAlignment(Qt::AlignCenter);
text.clear();
}
16.主函数
所有需要操作的都写在了主界面中,不需要更改Qt默认生成的主函数
四.注意事项
1.头文件
主界面所需的头文件
#include <QWidget>
#include <QMessageBox>
#include <QLabel>
#include <QKeyEvent>
#include <QTimer>
#include <QThread>
#include <QPushButton>
#include <QPainter>
#include <QPoint>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QString>
#include "map.h"
#include "hero.h"
#include "monster.h"
玩家类和怪物类只需要QString的头文件
2.图片与音乐文件
素材图片最好是.png格式的,背景图片任何类型都可以
背音乐文件一般为.wav格式,若想要使用其他格式则需要安装插件
当音乐文件放在项目.qrc文件下时,写音乐路径时必须在分号前写上"qrc"
如:QUrl("qrc:/bgm/morning.mp3");
当文件未放入项目中时,该路径必须是绝对路径