Qt推箱子小游戏和飞机大战项目实战

1.推箱子小游戏

  • QT./代表的当前目录位置

项目结构

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

效果图

  • GameMap.h
#ifndef GAMEMAP_H
#define GAMEMAP_H

#include <QObject>
#include <QPainter>

enum MapElement
{
    Road,
    Wall,
    Box,
    Point,
    InPoint
};

class GameMap : public QObject
{
    Q_OBJECT
public:
    explicit GameMap(QObject *parent = nullptr);

    ~GameMap();

    bool InitByFile(QString fileName);
    void Clear();
    void Paint(QPainter* _p,QPoint _Pos);

    int mRow;
    int mCol;
    int** mPArr;//用于开辟二维数组 2D地图元素

signals:

public slots:
};

#endif // GAMEMAP_H

  • GameMap.cpp
#include "GameMap.h"
#include <QFile>
#include <QDebug>

GameMap::GameMap(QObject *parent) : QObject(parent)
{
    mRow = 0;
    mCol = 0;
    mPArr = nullptr;

}
GameMap::~GameMap()
{
    Clear();
}

void GameMap::Clear()
{
    if(mPArr != nullptr)
    {
        for(int i = 0;i < mRow;i++)
        {
            delete[] mPArr[i];
        }
        delete[] mPArr;
    }
}


bool GameMap::InitByFile(QString fileName)
{
    QFile file(fileName);//创建文件对象
    if(!file.open(QIODevice::ReadOnly))
    {
        return false;//打开失败
    }

    //读取所有内容
    QByteArray arrAll = file.readAll();
    arrAll.replace("\r\n","\n");//将 "\r\n" 替换成 “\n”
    QList<QByteArray> lineList = arrAll.split('\n');//以“\n” 分割子串
    mRow = lineList.size();//确定行
    mPArr = new int*[mRow];

    for(int i = 0;i < mRow;i++)
    {
        QList<QByteArray> colList = lineList[i].split(',');
        mCol = colList.size();//确定列
        mPArr[i] = new int[mCol];//开辟列

        for(int j = 0;j < mCol;j++)//遍历列
        {
            mPArr[i][j] =  colList[j].toInt();
        }

    }
}

void GameMap::Paint(QPainter* _p, QPoint _Pos)
{
    for(int i = 0;i <mRow;i++)
    {
        for(int j = 0;j < mCol;j++)
        {
            QString imgUrl;
            switch (mPArr[i][j])
            {
                case Road: imgUrl = "://Image/sky.png";break;
                case Wall: imgUrl = "://Image/wall.png";break;
                case Box: imgUrl = "://Image/case.png";break;
                case Point: imgUrl = "://Image/end.png";break;
                case InPoint: imgUrl = "://Image/win.png";break;
            }
            QImage img(imgUrl);
            _p->drawImage(QRect(_Pos.x() + j*img.width(),_Pos.y() +i*img.height(),img.width(),img.height()),img);
//            _p->drawImage(_Pos,img);
        }
    }
}

  • Role.h
#ifndef ROLE_H
#define ROLE_H

#include <QObject>
#include <QPoint>
#include <QImage>

class Role : public QObject
{
    Q_OBJECT
public:
    explicit Role(QObject *parent = nullptr);

    //对应在地图的映射行列
    int mRow;
    int mCol;
    //画图位置
    //人在二维数组里的x,y和显示的x,y坐标轴是反过来的
    QPoint mPaintPos;
    //人物图片
    QImage mImg;

    void Move(int _dRow,int _dCol);//移动函数
    void Paint(QPainter* _p,QPoint _pos);//自己的绘制函数

signals:

public slots:
};

#endif // ROLE_H

  • Role.cpp
#include "Role.h"
#include <QPainter>

Role::Role(QObject *parent) : QObject(parent)
{
    mRow = 1;
    mCol = 1;
    mImg = QImage("://Image/people.png");

    //显示位置
    mPaintPos = QPoint(mCol,mRow) * mImg.width();

}

void Role::Move(int _dRow,int _dCol)
{
    mRow += _dRow;
    mCol += _dCol;

    mPaintPos = QPoint(mCol,mRow) * mImg.width();

}

void Role::Paint(QPainter* _p,QPoint _pos)
{
    _p->drawImage(mPaintPos + _pos,mImg);

}



  • Widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "GameMap.h"
#include "Role.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    virtual void paintEvent(QPaintEvent* event);//绘图事件函数
    virtual void keyPressEvent(QKeyEvent* event);//键盘按下事件
    void Collision(int _dRow,int _dCol);

    ~Widget();

private:
    Ui::Widget *ui;

    GameMap* mPMap;

    //画家
    QPainter* mMapPainter;

    //角色
    Role* mRole;
    //游戏更新定时器 解决paintEvent不定时更新问题
    QTimer* mTimer;
};

#endif // WIDGET_H

  • Widget.cpp
#include "Widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QPainter>
#include <QMessageBox>
#include <QKeyEvent>
#include <QtDebug>
#include <QTimer>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //初始化地图元素
    mPMap = new GameMap(this);
//    QString fileName =QFileDialog::getOpenFileName(this,"打开地图","./","*.txt");
    if(!mPMap->InitByFile("./Map/lv1.txt"))
    {
        QMessageBox::warning(this,"警告","文件打开失败");
    }

    mMapPainter = new QPainter(this);//创建画家
    mRole = new Role(this);
    //定时调用更新函数
    mTimer = new QTimer(this);
    mTimer->start(100);

    //定时调用更新函数
    connect(mTimer,&QTimer::timeout,[this](){this->update();});

    setFixedSize(1024,768);//固定窗口大小



}

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



void Widget::paintEvent(QPaintEvent *event)
{
    mMapPainter->begin(this);//设置画布

    //画背景
    QPainter bgPainter(this);
    bgPainter.drawImage(QRect(0,0,1024,768),QImage("://Image/ground.png"));


    //画地图
    mPMap->Paint(mMapPainter,QPoint(10,200));

    //画人物
    mRole->Paint(mMapPainter,QPoint(10,200));

    mMapPainter->end();//结束
}


void Widget::keyPressEvent(QKeyEvent* event)
{
    switch (event->key())
    {
    case Qt::Key_W:
    case Qt::Key_Up:
    {
        //逻辑碰撞检测函数
        Collision(-1,0);
        break;
    }
    case Qt::Key_S:
    case Qt::Key_Down:
    {
        //逻辑碰撞检测函数
        Collision(1,0);
        break;
    }
    case Qt::Key_A:
    case Qt::Key_Left:
    {
        //逻辑碰撞检测函数
        Collision(0,-1);
        break;
    }
    case Qt::Key_D:
    case Qt::Key_Right:
    {
        //逻辑碰撞检测函数
        Collision(0,1);
        break;
    }

    }
}


void Widget::Collision(int _dRow,int _dCol)
{
    //判断位置定义
    int newRow = mRole->mRow + _dRow;
    int newCol = mRole->mCol + _dCol;

    if(mPMap->mPArr[newRow][newCol] == Wall)//判断前方是墙
    {
        return;
    }
    else if(mPMap->mPArr[newRow][newCol] == Box)//判断前方是箱子
    {
        //判断箱子前方
        if(mPMap->mPArr[newRow+_dRow][newCol + _dCol] == Road)
        {
            //改变地图元素
            mPMap->mPArr[newRow+_dRow][newCol + _dCol] = Box;//箱子前方变成箱子
            mPMap->mPArr[newRow][newCol] = Road;

        }
        else if(mPMap->mPArr[newRow+_dRow][newCol + _dCol] == Point)
        {
            //改变地图元素
            mPMap->mPArr[newRow+_dRow][newCol + _dCol] = InPoint;//箱子前方变成进目标点
            mPMap->mPArr[newRow][newCol] = Road;
        }
        else
        {
            return;//无法推动箱子
        }
    }
    else if(mPMap->mPArr[newRow][newCol] == InPoint)//前方是进目标点(箱子与目标重合)
    {
        //判断目标点前方
        if(mPMap->mPArr[newRow+_dRow][newCol + _dCol] == Road)
        {
            //改变地图元素
            mPMap->mPArr[newRow+_dRow][newCol + _dCol] = Box;//目标点前方变成箱子
            mPMap->mPArr[newRow][newCol] = Point;

        }
        else if(mPMap->mPArr[newRow+_dRow][newCol + _dCol] == Point)
        {
            //改变地图元素
            mPMap->mPArr[newRow+_dRow][newCol + _dCol] = InPoint;//箱子进点
            mPMap->mPArr[newRow][newCol] = Point;
        }
        else
        {
            return;//无法推动箱子
        }

    }

    //否则移动
    mRole->Move(_dRow,_dCol);

    qDebug() << "人物绘制位置:" << mRole->mPaintPos;
}


2.飞机大战项目实战

2.1注意事项

  • 如何制作合适的图片
    p48集12:40开始看
  • 子弹位置的设计

添加音乐注意事项

扫描二维码关注公众号,回复: 15854543 查看本文章

导入资源

继承体系

2.2目录结构

2.3代码

  • 程序运行结果图

  • bullet.h
#ifndef BULLET_H
#define BULLET_H

#include "gameobject.h"


class Bullet : public GameObject
{
public:
    //子弹类型
    enum BulletType
    {
        BT_Player,//我方
        BT_Enemy//地方
    };

    explicit Bullet(QObject *parent = nullptr);
    Bullet(QPoint _pos,QPixmap _pixmap,int _type);

    //移动函数
    void BulletMove(QPoint _dir = QPoint(0,-1));

    //初始化函数
    void Init(QPoint _pos,QPixmap _pixmap);

    ~Bullet()
    {
        qDebug() << "子弹被释放";
    }

protected:
    int mBulletType;
    int mSpeed;
    QMediaPlayer mMedia;







};

#endif // BULLET_H

  • bullet.cpp
#include "bullet.h"

Bullet::Bullet(QObject *parent)
{
    mObjectType = GameObject::OT_BulletPlayer;
}

Bullet::Bullet(QPoint _pos, QPixmap _pixmap, int _type)
{
    this->setPos(_pos);
    this->setPixmap(_pixmap);
    this->mBulletType = _type;
    mSpeed = 6;




}

void Bullet::BulletMove(QPoint _dir)
{
    this->moveBy(_dir.x()*mSpeed,_dir.y()*mSpeed);
}


void Bullet::Init(QPoint _pos, QPixmap _pixmap)
{
    this->setPos(_pos);
    this->setPixmap(_pixmap);

    //----子弹微调整
    this->setScale(0.5);//缩放
    this->setX(this->x() - this->scale() * pixmap().width()/2);

}

  • enemy.h
#ifndef ENEMY_H
#define ENEMY_H

#include "plane.h"

class Enemy : public Plane
{

public:
    Enemy()
    {
        mObjectType = GameObject::OT_Enemy;//标识对象
    }

    Enemy(QPoint _pos,QPixmap _pixmap);

    void EnemyMove(QPoint _dir = QPoint(0,1));

    void Init(QPoint _pos,QPixmap _pixmap);



};

#endif // ENEMY_H

  • enemy.cpp
#include "enemy.h"

Enemy::Enemy(QPoint _pos, QPixmap _pixmap)
{
    this->mMoveSpeed = 3;
    this->mShootSpeed = 1000;
    this->setPos(_pos);
    this->setPixmap(_pixmap);
}

void Enemy::EnemyMove(QPoint _dir)
{
    this->moveBy(_dir.x()*mMoveSpeed ,_dir.y()*mMoveSpeed);
}

void Enemy::Init(QPoint _pos, QPixmap _pixmap)
{
    this->setPos(_pos);
    this->setPixmap(_pixmap);
    this->mMoveSpeed = 3;
    this->mShootSpeed = 1000;
}

  • enemybullet.h
#ifndef ENEMYBULLET_H
#define ENEMYBULLET_H

#include "bullet.h"

class EnemyBullet : public Bullet
{

public:
    explicit EnemyBullet(QObject *parent = nullptr);
    void PlaySound();


};

#endif // ENEMYBULLET_H

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(Qt实战项目,C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

-enemybullet.cpp

#include "enemybullet.h"

EnemyBullet::EnemyBullet(QObject *parent)
{
    mObjectType = GameObject::OT_EnemyBullet;
}

void EnemyBullet::PlaySound()
{
    mMedia.setMedia(QUrl("qrc:/sound/music/weapon_enemy.wav"));
    mMedia.play();
}

  • gamecontrol.h
#ifndef GAMECONTROL_H
#define GAMECONTROL_H

#include "gamedefine.h"
#include "widget.h"

class GameControl : public QObject
{
    //单例
    GameControl(QWidget* parent = nullptr);
    static GameControl* instance;
public:
    //获取单例
    static GameControl* Instance()
    {
        if(instance == nullptr)
        {
            return instance = new GameControl(Widget::widget);
        }
        return instance;
    }
    //析构
    ~GameControl()
    {
        qDebug() << "游戏控制释放";
    }

    //游戏初始化
    void GameInit();
    void LoadStartScene();//加载开始场景
    void LoadGameScene();//游戏场景加载

    //游戏逻辑定时器开启 (游戏开始)
    void GameStart();

    //游戏逻辑定时器关闭 (游戏结束)
    void GameOver();

    //背景移动
    void BGMove();

    //飞机移动函数
    void PlaneMove();



    //我机子弹生成函数
    void PlaneBulletShoot();
    //敌机生成
    void CreateEnemy();
    //碰撞检测
    void Collision();


    QList<int> mKeyList;//按键组合
protected:

    QGraphicsView mGameView;//游戏视图
    QGraphicsScene mGameScene;//游戏场景
    QGraphicsScene mStartScene;//开始游戏场景

    //场景元素
    QGraphicsPixmapItem mBackGround1;//背景元素
    QGraphicsPixmapItem mBackGround2;
    Player mPlane;

    //定时器
    QTimer* mBGMoveTimer;//背景移动
    QTimer* mPlaneMoveTimer;//飞机移动
    QTimer* mPlaneShootTimer;//飞机发射定时器
    QTimer* mBulletMoveTimer;//子弹移动定时器
    QTimer* mEnemyCreateTimer;//敌机创建定时器
    QTimer* mEnemyMoveTimer;//敌机创建定时器


    //容器
    QList<Bullet*> mBulletList;//子弹容器
    QList<Enemy*> mEnemyList;//敌机容器

    //背景音乐
    QMediaPlayer* mMediaBG;




};

#endif // GAMECONTROL_H

  • gamecontrol.cpp
#include "gamecontrol.h"
#include "gamedefine.h"
#include "gameobjectpool.h"

GameControl* GameControl::instance = nullptr;

GameControl::GameControl(QWidget* parent) : QObject  (parent)
{
//    this->setParent(Widget::widget);
}

void GameControl::BGMove()
{
    mBackGround2.moveBy(0,2);
    mBackGround1.moveBy(0,2);//moveBy 移动量  dx--x方向移动量  dy---y方向移动量

    if(mBackGround1.y() >= mBackGround1.pixmap().height())
    {
        mBackGround1.setY(-mBackGround1.pixmap().height());
    }
    else if(mBackGround2.y() >= mBackGround2.pixmap().height())
    {
        mBackGround2.setY(-mBackGround2.pixmap().height());
    }
}

void GameControl::GameInit()
{

    //对象池初始化
    GameObjectPool::Instance()->Init();

    //设置视图的父亲为窗口
    mGameView.setParent(Widget::widget);

    //开始场景初始化
    LoadStartScene();

    //定时器初始化
    mBGMoveTimer = new QTimer(Widget::widget);
    mPlaneMoveTimer = new QTimer(Widget::widget);
    mPlaneShootTimer = new QTimer(Widget::widget);
    mBulletMoveTimer = new QTimer(Widget::widget);
    mEnemyCreateTimer = new QTimer(Widget::widget);
    mEnemyMoveTimer = new QTimer(Widget::widget);

    //绑定定时器处理函数
    connect(mBGMoveTimer,&QTimer::timeout,this,&GameControl::BGMove);
    connect(mPlaneMoveTimer,&QTimer::timeout,this,&GameControl::PlaneMove);
    connect(mPlaneShootTimer,&QTimer::timeout,this,&GameControl::PlaneBulletShoot);
    connect(mEnemyCreateTimer,&QTimer::timeout,this,&GameControl::CreateEnemy);
    connect(mBulletMoveTimer,&QTimer::timeout,[this](){
            //子弹移动
            for(auto bullet : mBulletList)
            {
                bullet->BulletMove();

                //判断越界回收子弹
                if(bullet->y() < -200)
                {
                    //移除场景 并回收对象
                    bullet->GameObjectDelete(&mGameScene);

                    //移除容器
                    mBulletList.removeOne(bullet);
                }
            }

            //碰撞检测
            Collision();
        });


    connect(mEnemyMoveTimer,&QTimer::timeout,[this](){
            for(auto enemy : mEnemyList)
            {
                enemy->EnemyMove();

                if(enemy->y() > GameDefine::ScreenHeight + enemy->pixmap().height())
                {
                    //移除场景 对象池回收对象
                    enemy->GameObjectDelete(&mGameScene);

                    //移除容器
                    mEnemyList.removeOne(enemy);
                }
            }
        });



}

void GameControl::LoadStartScene()
{
    mStartScene.setSceneRect(QRect(0,0,512,768));//游戏开始场景大小
    mStartScene.addPixmap(QPixmap(":/img/Image/img_bg_logo.jpg"));

    auto startBtn = new QToolButton();
    startBtn->setAutoRaise(true);
    startBtn->setIcon(QIcon(":/img/Image/startBtn.fw.png"));
    startBtn->setIconSize(QSize(171,45));
    startBtn->move(256-171/2,384);
    //开始游戏点击
    connect(startBtn,&QToolButton::clicked,[this](){

        //加载游戏场景
        this->LoadGameScene();
        //开始游戏
        this->GameStart();

    });
    mStartScene.addWidget(startBtn);

    //设置当前场景为 开始场景
    mGameView.setScene(&mStartScene);
    mGameView.show();

}

void GameControl::LoadGameScene()
{
    mGameScene.setSceneRect(QRect(0,0,512,768));//游戏进行场景大小
    mBackGround1.setPixmap(QPixmap(":/img/Image/img_bg_level_2.jpg"));//于QImage用法类似
    mBackGround2.setPixmap(QPixmap(":/img/Image/img_bg_level_2.jpg"));
    mPlane.setPixmap(QPixmap(":/img/Image/MyPlane1.fw.png"));

    //设置元素位置
    mBackGround2.setPos(0,-mBackGround2.pixmap().height());

    //图片元素添加到场景
    mGameScene.addItem(&mBackGround1);
    mGameScene.addItem(&mBackGround2);
    mGameScene.addItem(&mPlane);



    //设置当前场景为游戏场景
    mGameView.setScene(&mGameScene);
    mGameView.show();


    //-------------播放音效
    this->mMediaBG = new QMediaPlayer(Widget::widget);
    //注意  QUrl路径对象 字符串格式 "qrc:/ + 前缀名+ /路径"
    this->mMediaBG->setMedia(QUrl("qrc:/sound/music/starwars.mp3"));
    this->mMediaBG->play();



}

void GameControl::GameStart()
{
    //开启定时器
    mBGMoveTimer->start(GameDefine::BackgroundUpdateTime);
    mPlaneMoveTimer->start(GameDefine::PlayerMoveUpdateTime);
    mPlaneShootTimer->start(GameDefine::PlaneShootUpdateTime);
    mBulletMoveTimer->start(GameDefine::BulletMoveUpdateTime);
    mEnemyCreateTimer->start(GameDefine::EnemyCreateTime);
    mEnemyMoveTimer->start(GameDefine::EnemyMoveUpdateTime);
}

void GameControl::GameOver()
{
    //结束逻辑
    //...
}


void GameControl::PlaneMove()
{
    for(int keyCode : mKeyList)
    {
        switch (keyCode)
        {
        case Qt::Key_W: mPlane.moveBy(0,-1 * mPlane.MoveSpeed());break;
        case Qt::Key_S: mPlane.moveBy(0,1*mPlane.MoveSpeed());break;
        case Qt::Key_A: mPlane.moveBy(-1*mPlane.MoveSpeed(),0);break;
        case Qt::Key_D: mPlane.moveBy(1*mPlane.MoveSpeed(),0);break;
        }
    }

    //*******************************边界判断
    if(mPlane.x() < 0)
    {
        mPlane.setX(0);
    }
    if(mPlane.y() < 0)
    {
        mPlane.setY(0);
    }
    if(mPlane.x() > GameDefine::ScreenWidth - mPlane.pixmap().width())
    {
        mPlane.setX(GameDefine::ScreenWidth - mPlane.pixmap().width());
    }
    if(mPlane.y() > GameDefine::ScreenHeight - mPlane.pixmap().height())
    {
        mPlane.setY(GameDefine::ScreenHeight - mPlane.pixmap().height());
    }
}



void GameControl::PlaneBulletShoot()
{
    //对象池构建子弹
    QPixmap bulletImg(":/img/Image/bulletPlane.fw.png");
    QPoint pos(mPlane.x() + mPlane.pixmap().width()/2,mPlane.y());
    GameObject* obj = GameObjectPool::Instance()->GetGameObject(GameObject::OT_BulletPlayer);
    PlayerBullet* bullet = (PlayerBullet*)obj;
    bullet->Init(pos,bulletImg);
    bullet->PlaySound();//播放音效

    //添加到场景
    mGameScene.addItem(bullet);

    //添加到子弹管理器
    mBulletList.append(bullet);
}

void GameControl::CreateEnemy()
{

//    Enemy* enemy = new Enemy(QPoint(randX,-200),pixmap);

    //对象池获取对象
    QPixmap pixmap(":/img/Image/enemy1.fw.png");
    int randX = qrand()%(512-pixmap.width());// [0,32768)
    GameObject* obj = GameObjectPool::Instance()->GetGameObject(GameObject::OT_Enemy);
    Enemy* enemy = (Enemy*)obj;
    enemy->Init(QPoint(randX,-200),pixmap);


    //添加到场景
    mGameScene.addItem(enemy);

    //添加到管理器
    mEnemyList.append(enemy);
}

void GameControl::Collision()
{
    //遍历子弹
    for(int i = 0;i < mBulletList.size();i++)
    {
        //遍历敌机
        for(int j = 0;j < mEnemyList.size();j++)
        {
            if(mBulletList[i]->collidesWithItem(mEnemyList[j]))//碰撞检测
            {
                //移除场景   (实际的对象并没有被删除)
//                mGameScene.removeItem(mBulletList[i]);
//                mGameScene.removeItem(mEnemyList[j]);

                //移除场景并回收到对象池
                mBulletList[i]->GameObjectDelete(&mGameScene);
                mEnemyList[j]->GameObjectDelete(&mGameScene);

                //移除管理器
                mBulletList.removeOne(mBulletList[i]);
                mEnemyList.removeOne(mEnemyList[j]);

            }
        }
    }
}

  • gamedefine.h
#ifndef GAMEDEFINE_H
#define GAMEDEFINE_H

#include <QtDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QTimer>
#include <QList>
#include <QToolButton>
#include <QMediaPlayer>
#include "bullet.h"
#include "enemy.h"
#include "player.h"
#include "playerbullet.h"
#include "enemybullet.h"


//游戏定义类  定义游戏相关属性

class GameDefine
{

public:
    GameDefine();
    static const int PlaneShootUpdateTime = 500;
    static const int PlayerMoveUpdateTime = 20;
    static const int EnemyMoveUpdateTime = 20;
    static const int BulletMoveUpdateTime = 10;
    static const int BackgroundUpdateTime = 50;
    static const int EnemyCreateTime = 2000;

    //屏幕宽高
    static const int ScreenWidth = 512;
    static const int ScreenHeight = 768;



};

#endif // GAMEDEFINE_H

  • gamedefine.cpp
#include "gamedefine.h"

GameDefine::GameDefine()
{

}
  • gameobject.h
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H

#include <QGraphicsPixmapItem>
#include <QDebug>
#include <QMediaPlayer>

class GameObject : public QGraphicsPixmapItem
{

public:
    enum ObjectType
    {
        OT_BulletPlayer,
        OT_Enemy,
        OT_Player,
        OT_EnemyBullet
    };


    explicit GameObject(QObject *parent = nullptr);
    int GetType()
    {
       return mObjectType;
    }

    //对象回收
    void GameObjectDelete(QGraphicsScene* _scene);

    //统计对象构造 和析构
    static int createCount;

    ~GameObject()
    {
        qDebug() << "当前释放第" + QString::number(createCount--) + "个对象";
    }

protected:
    int mObjectType;

};

#endif // GAMEOBJECT_H

  • gameobject.cpp`
#include "gameobject.h"
#include <QGraphicsScene>
#include "gameobjectpool.h"
#include  <QDebug>

int GameObject::createCount = 0;
GameObject::GameObject(QObject *parent)
{
    createCount++;
    qDebug() << "当前创建" + QString::number(createCount) + "个对象";
}

void GameObject::GameObjectDelete(QGraphicsScene* _scene)
{
    _scene->removeItem(this);//移除场景
    GameObjectPool::Instance()->RecoveryGameObject(this);//回收对象
}

  • gameobjectpool.h
#ifndef GAMEOBJECTPOOL_H
#define GAMEOBJECTPOOL_H

#include <QObject>
#include "gamedefine.h"
#include "widget.h"

/*
 *
 * 当对象被频繁创建 或 删除时  大量使用 new 和  delete 关键字
处理堆内存  如果该对象比较大  则对计算机的消耗就越大  很有可以在创建大量
对象时出现卡顿情况  频繁的创建和删除对计算机消耗比较大。


对象缓存池:对象缓存池 预先缓存一定数量的对象  对象需要被
使用时 直接从对象池中获取对象 能有效的解决在创建时导致的卡顿问题。在对象
需要被消耗时 不销毁对象将其回收到对象缓存池中 循环利用从而解决对计算机的
销毁。
(简单来说 就是游戏对象的循环利用)


*/


class GameObjectPool : public QObject
{
    GameObjectPool(QObject *parent = nullptr);
    static GameObjectPool* instance;
public:
    static GameObjectPool* Instance()
    {
        if(instance == nullptr)
        {
            return instance = new GameObjectPool(Widget::widget);
        }
        return instance;
    }

    //对象池初始化  缓存对象
    void Init();

    //获取对象
    GameObject* GetGameObject(int _objectType);

    //对象回收
    void RecoveryGameObject(GameObject* _object);

    //内存清除
    void Clear();

    ~GameObjectPool();

protected:
    //玩家子弹对象池容器
    QList<PlayerBullet*> mBulletPool;

    //敌机对象池容器
    QList<Enemy*> mEnemyPool;

};

#endif // GAMEOBJECTPOOL_H

  • gameobjectpool.cpp
#include "gameobjectpool.h"


GameObjectPool* GameObjectPool::instance = nullptr;

GameObjectPool::GameObjectPool(QObject *parent) : QObject(parent)
{

}

void GameObjectPool::Init()
{
    //预先生产对象
    for (int i = 0;i < 20; i++)
    {
        //子弹生产
        PlayerBullet* bullet = new PlayerBullet();
        mBulletPool.append(bullet);

        //敌机生产
        Enemy* enemy = new Enemy();
        mEnemyPool.append(enemy);

    }
}

GameObject *GameObjectPool::GetGameObject(int _objectType)
{
    switch (_objectType)
    {
    case GameObject::OT_BulletPlayer://子弹
    {
        PlayerBullet* bullet = mBulletPool.first();
        mBulletPool.pop_front();

        return bullet;
    }
    case GameObject::OT_Enemy://敌机
    {
        Enemy* enemy = mEnemyPool.first();
        mEnemyPool.pop_front();

        return enemy;
    }

    }
}

void GameObjectPool::RecoveryGameObject(GameObject *_object)
{
    switch (_object->GetType())
    {
    case GameObject::OT_BulletPlayer://子弹
    {
        mBulletPool.append((PlayerBullet*)_object);
        break;
    }
    case GameObject::OT_Enemy://敌机
    {
        mEnemyPool.append((Enemy*)_object);
        break;
    }
    }
}

void GameObjectPool::Clear()
{
    //清除子弹容器
    for(auto pBullet : mBulletPool)
    {
        delete pBullet;
    }
    //清除敌机容器
    for(auto pEnemy :mEnemyPool)
    {
        delete pEnemy;
    }


}

GameObjectPool::~GameObjectPool()
{
    Clear();//内存清除
}

  • plane.h
#ifndef PLANE_H
#define PLANE_H

#include "gameobject.h"

class Plane : public GameObject
{

public:
    explicit Plane(QObject *parent = nullptr);

    float MoveSpeed()
    {
        return mMoveSpeed;
    }

protected:
    float mMoveSpeed;
    int mShootSpeed;

};

#endif // PLANE_H

  • plane.cpp
#include "plane.h"

Plane::Plane(QObject *parent)
{
    mObjectType = GameObject::OT_Player;
}

  • player.h
#ifndef MYPLANE_H
#define MYPLANE_H

#include "plane.h"

class Player : public Plane
{
//    Q_OBJECT  QGraphicsItem的派生类 不支持 Q_OBJECT(老式 信号和槽 宏)
public:
    Player();


};

#endif // MYPLANE_H

  • player.cpp
#include "player.h"

Player::Player()
{
    this->setPixmap(QPixmap(":/img/Image/MyPlane1.fw.png"));
    this->setPos(256,500);

    mMoveSpeed = 5;
    mShootSpeed = 500;
}

  • playerbullet.h
#ifndef PLAYERBULLET_H
#define PLAYERBULLET_H

#include "bullet.h"

class PlayerBullet : public Bullet
{

public:
    explicit PlayerBullet(QObject *parent = nullptr);

    //玩家子弹音效
    void PlaySound();

signals:

public slots:
};

#endif // PLAYERBULLET_H

  • playerbullet.cpp
#include "playerbullet.h"

PlayerBullet::PlayerBullet(QObject *parent)
{
   mObjectType = GameObject::OT_BulletPlayer;
   mSpeed = 6;
}

void PlayerBullet::PlaySound()
{
   mMedia.setMedia(QUrl("qrc:/sound/music/weapon_player.wav"));
   mMedia.play();
}

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGraphicsPixmapItem>//图形元素
#include <QGraphicsView>//视图
#include <QGraphicsScene>//场景
#include <QList>//链表
#include "enemy.h"
#include "player.h"
#include "bullet.h"
#include <QMediaPlayer>//媒体播放器类

//   图形元素组成  ---> 场景  --> 视图  --> 窗口

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

    static Widget* widget;

    //按键事件  widget才能检测到这两个函数
    void keyPressEvent(QKeyEvent* event);
    void keyReleaseEvent(QKeyEvent* event);

private:
    Ui::Widget *ui;

};

#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "gamecontrol.h"
#include "student.h"

Widget* Widget::widget = nullptr;

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setFixedSize(512,768);
    widget = this;//拿到widget,防止使用this报错

    GameControl::Instance()->setParent(this);

}

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


void Widget::keyPressEvent(QKeyEvent *event)
{
    //添加按键到按键组合
    switch (event->key())
    {
        case Qt::Key_W:
        case Qt::Key_S:
        case Qt::Key_A:
        case Qt::Key_D:
        GameControl::Instance()->mKeyList.append(event->key());
        break;

    }
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    //移除对应按键组合
   if(GameControl::Instance()->mKeyList.contains(event->key()))
   {
       GameControl::Instance()->mKeyList.removeOne(event->key());
   }

}


  • main.cpp
#include <QApplication>
#include "gamecontrol.h"
#include "student.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    //游戏加载
    GameControl::Instance()->GameInit();


    return a.exec();
}

3.XMl学习

3.1注意点

  • 快速判断xml文件是否写错
    将文件直接拖入浏览器中,如果能正常打开就是没错的
  • HeroInfo.xml

Config.xml

3.2目录结构

  • 目录结构

3.2代码

  • Hero.h
#ifndef HERO_H
#define HERO_H

#include <QObject>
class Hero
{
public:
    Hero();
    Hero(QString name,int atk,int def,int hp,QString des)
    {
        mName = name;
        mAtk  =atk;
        mHp = hp;
        mDef = def;
        mDescript = des;

    }

    QString mName;
    int mAtk;
    int mDef;
    int mHp;
    QString mDescript;
};

#endif // HERO_H

  • Hero.cpp
#include "Hero.h"

Hero::Hero()
{

}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_LoadBtn_clicked();

    void on_SaveBtn_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

  • Widget.cpp
#include "Widget.h"
#include "ui_widget.h"
#include <QtXML>  //需导入QtXML,并且执行qmake
#include "Hero.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->textEdit->setReadOnly(true);
}

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

void Widget::on_LoadBtn_clicked()
{
    //构建文件对象 QFile
    QFile file("HeroInfo.xml");
    if(!file.open(QIODevice::ReadOnly))//打开文件用于读取
        return;

    //**************XML文件读取*************
    QDomDocument doc;//创建文档对象
    doc.setContent(&file);//设置文档内容,将file和doc绑定起来
//    doc.setContent(file.readAll());//设置文档内容

    QDomElement root = doc.firstChildElement("Root");//获取第一个子标签
    QDomElement hero = root.firstChildElement("Hero");//获取hero子标签

    QString text;
    while (!hero.isNull())//判断hero标签是否存在
    {
        text += "Name:" + hero.attribute("name");//读取属性
        text += "  Atk:" + hero.attribute("atk");
        text += "  Def:" + hero.attribute("def");
        text += "  HP:" + hero.attribute("hp");

        //读取标签内容
        text += "  Des:" + hero.text()+"\n";

        hero = hero.nextSiblingElement("Hero");//获取下一个Hero兄弟标签
    }
    ui->textEdit->setText(text);

    file.close();



}

void Widget::on_SaveBtn_clicked()
{
    QVector<Hero> vec;
    vec.push_back(Hero("曹操",100,25,2000,"曹孟德"));
    vec.push_back(Hero("曹丕",100,25,2000,"曹子桓"));
    vec.push_back(Hero("曹植",100,25,2000,"曹子建"));
    vec.push_back(Hero("曹彰",100,25,2000,"曹xx"));
    vec.push_back(Hero("曹真",100,25,2000,"曹xx"));

    //创建xml文档对象
    QDomDocument doc;
    QDomElement root = doc.createElement("Root");//创建root标签

    for(int i =0;i < vec.count();i++)
    {
        QDomElement hero = doc.createElement("Hero");//创建hero标签
        root.appendChild(hero);

        hero.setAttribute("Name",vec[i].mName);//设置属性 Name
        hero.setAttribute("Atk",vec[i].mAtk);
        hero.setAttribute("Def",vec[i].mDef);
        hero.setAttribute("HP",vec[i].mHp);

        QDomText text = doc.createTextNode(vec[i].mDescript);
        hero.appendChild(text);
    }
    doc.appendChild(root);//将root节点添加到文档对象

    //创建文件对象
    QFile file("./Config.xml"); //采用相对路径
    if(!file.open(QIODevice::WriteOnly))
        return;

    QTextStream outStream(&file);//创建文本流对象
    doc.save(outStream,4);
    file.close();


}

原文地址:QT项目实战_余甘不甘的博客-CSDN博客

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓ 

猜你喜欢

转载自blog.csdn.net/m0_73443478/article/details/131898526