QT项目实战

白色玫瑰 程序猿

时间: 2023-07-16 阅读: 1 字数:33690

{}
QT./代表的当前目录位置 项目结构 效果图 GameMap.h #ifndef GAMEMAP_H #define GAMEMAP_H #include <QObject> #include <QPainter> enum MapElement { Road, Wall, Box, Point, InPoint }; ...

1.推箱子小游戏

QT./代表的当前目录位置 在这里插入图片描述 项目结构 在这里插入图片描述 效果图 请添加图片描述 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,&amp;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开始看 子弹位置的设计 在这里插入图片描述

添加音乐注意事项 在这里插入图片描述 在这里插入图片描述 导入资源 在这里插入图片描述 继承体系 在这里插入图片描述

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

-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,&amp;QTimer::timeout,this,&amp;GameControl::BGMove);
   connect(mPlaneMoveTimer,&amp;QTimer::timeout,this,&amp;GameControl::PlaneMove);
   connect(mPlaneShootTimer,&amp;QTimer::timeout,this,&amp;GameControl::PlaneBulletShoot);
   connect(mEnemyCreateTimer,&amp;QTimer::timeout,this,&amp;GameControl::CreateEnemy);
   connect(mBulletMoveTimer,&amp;QTimer::timeout,[this](){
         //子弹移动
         for(auto bullet : mBulletList)
         {
            bullet->BulletMove();

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

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

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


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

            if(enemy->y() > GameDefine::ScreenHeight + enemy->pixmap().height())
            {
               //移除场景 对象池回收对象
               enemy->GameObjectDelete(&amp;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,&amp;QToolButton::clicked,[this](){

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

   });
   mStartScene.addWidget(startBtn);

   //设置当前场景为 开始场景
   mGameView.setScene(&amp;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(&amp;mBackGround1);
   mGameScene.addItem(&amp;mBackGround2);
   mGameScene.addItem(&amp;mPlane);



   //设置当前场景为游戏场景
   mGameView.setScene(&amp;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(&amp;mGameScene);
            mEnemyList[j]->GameObjectDelete(&amp;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(&amp;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(&amp;file);//创建文本流对象
   doc.save(outStream,4);
   file.close();


}














原文地址:https://blog.csdn.net/qq_48621751/article/details/123227303?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168949707716800215098447%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168949707716800215098447&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-26-123227303-null-null.142^v88^insert_down1,239^v2^insert_chatgpt&utm_term=%E6%80%8E%E4%B9%88%E6%89%93%E5%BC%80qt6%E9%A1%B9%E7%9B%AE

本文章网址:https://www.sjxi.cn/detil/1258ba0d8d3b4c42a8d231fd0557827d

最新评论

当前未登陆哦
登陆后才可评论哦

湘ICP备2021009447号

×

(穷逼博主)在线接单

QQ: 1164453243

邮箱: abcdsjx@126.com

前端项目代做
前后端分离
Python 爬虫脚本
Java 后台开发
各种脚本编写
服务器搭建
个人博客搭建
Web 应用开发
Chrome 插件编写
Bug 修复