Qt编写魔塔小游戏

目录

一.游戏大致内容

        1.玩家角色

        2.怪物

        3.可触发的物品

        4.不可触发的物品

        5.地图

        6.(玩家与怪物的技能)

二.实现逻辑

三.具体实现

1.角色类声明

2.怪物类声明

3.地图类声明

4.主界面声明

5.玩家角色的构造

6.怪物的构造

7.地图的构造

8.主界面构造

9.开始按钮的槽函数与绘图事件

10.键盘事件处理

11.初始化地图界面

12.刷新地图界面

13.角色移动处理

14.运算战斗结果

15.边栏角色信息

16.主函数

四.注意事项

        1.头文件

        2.图片与音乐文件

        3.项目整体

五.游戏效果

        1.开始界面(简陋)

        2.第一层(新手大剑)

         3.第二层(开始正常游戏)

        4.后续层

        5.奖励层

        6.最后一层(暂时还没写结束结算)


最近系统学习了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;isetFixedSize(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

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;kmap[k][i][j]=static_map->map[k][i][j];
                }
            }
        }
        //判断角色死亡,是否重新开始。
        restart_signal=false;
    }
    //绘制当前地图
    for(int i=0;iclear();
            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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "map.h"
#include "hero.h"
#include "monster.h"

                玩家类和怪物类只需要QString的头文件

        2.图片与音乐文件

                素材图片最好是.png格式的,背景图片任何类型都可以

                背音乐文件一般为.wav格式,若想要使用其他格式则需要安装插件

                当音乐文件放在项目.qrc文件下时,写音乐路径时必须在分号前写上"qrc"

                如:QUrl("qrc:/bgm/morning.mp3");

                当文件未放入项目中时,该路径必须是绝对路径

        3.项目整体

Qt编写魔塔小游戏_第1张图片

五.游戏效果

        1.开始界面(简陋)

        2.第一层(新手大剑)

Qt编写魔塔小游戏_第2张图片

         3.第二层(开始正常游戏)

Qt编写魔塔小游戏_第3张图片

        4.后续层

Qt编写魔塔小游戏_第4张图片Qt编写魔塔小游戏_第5张图片

Qt编写魔塔小游戏_第6张图片Qt编写魔塔小游戏_第7张图片

        5.奖励层

Qt编写魔塔小游戏_第8张图片

        6.最后一层(暂时还没写结束结算)

Qt编写魔塔小游戏_第9张图片

你可能感兴趣的:(qt,开发语言,c++)