我想做卖鱼苗网站怎样做嵌入式工程师要学什么
- 作者: 五速梦信息网
- 时间: 2026年04月20日 07:15
当前位置: 首页 > news >正文
我想做卖鱼苗网站怎样做,嵌入式工程师要学什么,企业展厅设计公司哪个好看,百度官方免费下载Qt planeGame day10
Game基本框架
qt中没有现成的游戏框架可以用#xff0c;我们需要自己搭框架首先创建一个QGame类作为框架#xff0c;这个基本框架里面应该有如下功能#xff1a;游戏初始化
void init(const QSize siez,const QString title);游戏反初始化(…Qt planeGame day10
Game基本框架
qt中没有现成的游戏框架可以用我们需要自己搭框架首先创建一个QGame类作为框架这个基本框架里面应该有如下功能游戏初始化
void init(const QSize siez,const QString title);游戏反初始化(清理)
void clean();更新游戏
void update(int);渲染游戏
void render(QPainter* painter);游戏是否在运行
bool isRunning() const;退出游戏
void quit();运行游戏
void runGame();设置游戏帧率
void setFps(qreal fps);一个游戏肯定要在一个主循环里面在Qt中肯定不能使用死循环就得使用定时器了基本的变量 //控制游戏进行的变量bool m_isRunning false;//游戏的主循环QTimer* m_mainLoopTimerP{};//游戏帧率60帧qreal m_fps 1000 / 60;基本框架思路判断游戏是否运行中运行中的话需要连接定时器处理游戏更新于绘图然后开启定时器因为qt的绘图只能在事件中完成所以把渲染写在事件中即可在定时器中去调用父类的更新画面基本框架
QGame.h
#ifndef QGAMEH
#define QGAMEH#include QWidget
#include Qtimerclass QGame :public QWidget
{Q_OBJECT
public:QGame(QWidget* parent nullptr);~QGame();//游戏初始化void init(const QSize size, const QString title);//游戏反初始化void clean();//更新游戏站位符与父类的方法做区别void update(int);//渲染游戏void render(QPainter* painter);//游戏是否进行bool isRuning() const;//退出游戏void quit();//运行游戏void runGame();//设置游戏帧率void setFps(qreal fps);//获取游戏帧数的接口qreal fps() const { return m_fps; }
protected:void paintEvent(QPaintEvent* ev) override;
private://控制游戏进行的变量bool m_isRunning false;//游戏的主循环QTimer* m_mainLoopTimer{};//游戏帧率60帧qreal m_fps 1000 / 60;
};#endifQGame.cpp
#include QGame.h
#include QApplication
#include QPainter
QGame::QGame(QWidget* parent) :QWidget(parent), m_mainLoopTimer(new QTimer)
{}
QGame::~QGame()
{//清理clean();
}
//游戏初始化
void QGame::init(const QSize size, const QString title)
{//设置窗口固定大小setFixedSize(size);//设置标题setWindowTitle(title);//因为上面会有各种资源的初始化如果初始化失败那么m_isRunningfalse;游戏不继续运行了//初始化成功就为true m_isRunning true;
}
//游戏反初始化
void QGame::clean()
{
}
//更新游戏
void QGame::update(int)
{
}
//渲染游戏
void QGame::render(QPainter* painter)
{
}
//游戏是否进行
bool QGame::isRuning() const
{return true;
}
//退出游戏
void QGame::quit()
{m_isRunning false;
}
//运行游戏
void QGame::runGame()
{ //显示窗口show();//连接定时器m_mainLoopTimer-callOnTimeout({//如果游戏没有在运行那么就结束游戏if (!isRuning()){m_mainLoopTimer-stop();qApp-quit();}//更新游戏,QGame的自定义updateupdate(0);//重绘,父类的updateQWidget::update();//测试游戏是否在进行qDebug() 游戏运行中;});//开始定时器设置游戏开启的帧数m_mainLoopTimer-start(m_fps);
}
//设置游戏帧率
void QGame::setFps(qreal fps)
{m_fps fps;
}//绘图事件
void QGame::paintEvent(QPaintEvent* ev)
{//开启画家QPainter painter(this);//渲染游戏render(painter);
}mian.cpp
#include QApplication
#include QGame.hint main(int argc,char* argv[])
{QApplication a(argc, argv);QGame game;game.init({ 600,600 }, 小瓜);game.runGame();return a.exec();
}运行结果游戏是在主循环中基本框架搭建完毕
构建精灵与实体类
实体类
新建一个Entity空类什么都不需要继承这个类里面可以存放各种实体我们统一称为精灵每一个精灵都会有一种状态例如是否死亡所以我们还需要存在一个类别用与判断实体类型。
private:bool m_active true;//实体是否是活动的int m_type 0;//实体类型那么这个实体被精灵继承的时候是需要更新释放渲染实体的所以这个实体类一定要有虚析构与纯虚方法不然子类可能释放不了造成内存泄漏
public:virtual ~Entity() {};//虚析构当子类继承重写的时候就可以释放子类的内存virtual void update() 0;//更新实体virtual void render(QPainter* painter);//渲染实体我们当前实体类中的方法可以设置状态的销毁与实体的类型到时候由一个统一的管理类去进行管理 //接口bool active()const { return m_active; }int type()const { return m_type; }//状态销毁void destory() { m_active false; }//设置实体类型void setType(int type) { m_type type; }Entity.h
#ifndef ENTITYH
#define ENTITYH#include QPainterclass Entity
{
public:virtual ~Entity() {};//虚析构当子类继承重写的时候就可以释放子类的内存virtual void update() 0;//更新实体virtual void render(QPainter* painter) 0;//渲染实体//接口bool active()const { return m_active; }int type()const { return m_type; }//状态销毁void destroy() { m_active false; }//设置实体类型void setType(int type) { m_type type; }private:bool m_active true;//精灵是否是活动的int m_type 0;//精灵类型};
#endif // !ENTITY_H_精灵类
新建一个精灵类这个类需要重写Entity的纯虚方法这个类拥有设置坐标与加载图片的方法
private:QPixmap m_image;QVector2D m_pos;设置图片
//设置图片
void setPixmap(const QString fileName, const QSize size QSize());设置坐标
//设置坐标
void setPos(float x, float y)
{m_pos { x,y };
}Sprite.h
#ifndef SPRITEH
#define SPRITEH#include Entity.h
#include QVector2Dclass Sprite :public Entity
{
public:Sprite() default;Sprite(const QString fileName, const QSize size QSize());//接口QVector2D getPos()const { return m_pos; }QPixmap getPixmap()const { return m_image; }//设置坐标void setPos(float x, float y){m_pos { x,y };}//设置图片void setPixmap(const QString fileName, const QSize size QSize());// 通过 Entity 继承void update() override;// 通过 Entity 继承void render(QPainter* painter) override;private:QPixmap m_image;QVector2D m_pos;
};
#endif // !SPRITE_H_Sprite.cpp
#include Sprite.hSprite::Sprite(const QString fileName, const QSize size)
{setPixmap(fileName, size);
}
//设置图片
void Sprite::setPixmap(const QString fileName, const QSize size)
{m_image.load(fileName);if (size.isValid()){//保持缩放 m_image.scaled(size, Qt::AspectRatioMode::KeepAspectRatio);}
}void Sprite::update()
{
}void Sprite::render(QPainter* painter)
{painter-drawPixmap(m_pos.toPoint(), m_image);
}QGame.cpp
在QGame.cpp中声明一个全局的精灵类然后去初始化精灵
#include QGame.h
#include Sprite.h
#include QApplication
#include QPainterQGame::QGame(QWidget* parent) :QWidget(parent), m_mainLoopTimer(new QTimer)
{}
QGame::~QGame()
{//清理clean();
}//全局精灵类,注意这里必须使用指针类如果是普通类对象会报错
//因为QT里面QApplication执行后是不允许对象还没有构造完的指针是个不完整类就不会默认构造
Sprite* player;//游戏初始化
void QGame::init(const QSize size, const QString title)
{//设置窗口固定大小setFixedSize(size);//设置标题setWindowTitle(title);player new Sprite;player-setPixmap(:/plane/Resource/images/hero1.png);//因为上面会有各种资源的初始化如果初始化失败那么m_isRunningfalse;游戏不继续运行了//初始化成功就为true m_isRunning true;
}
//游戏反初始化
void QGame::clean()
{
}
//更新游戏
void QGame::update(int)
{player-update();
}
//渲染游戏
void QGame::render(QPainter* painter)
{player-render(painter);
}
//游戏是否进行
bool QGame::isRuning() const
{return true;
}
//退出游戏
void QGame::quit()
{m_isRunning false;
}
//运行游戏
void QGame::runGame()
{ //显示窗口show();//连接定时器m_mainLoopTimer-callOnTimeout({//如果游戏没有在运行那么就结束游戏if (!isRuning()){m_mainLoopTimer-stop();qApp-quit();}//更新游戏,QGame的自定义updateupdate(0);//重绘,父类的updateQWidget::update();//测试游戏是否在进行qDebug() 游戏运行中;});//开始定时器设置游戏开启的帧数m_mainLoopTimer-start(m_fps);
}
//设置游戏帧率
void QGame::setFps(qreal fps)
{m_fps fps;
}//绘图事件
void QGame::paintEvent(QPaintEvent* ev)
{//开启画家QPainter painter(this);//渲染游戏render(painter);
}运行结果
精灵移动
毫无疑问我们需要让精灵动起来那肯定得使用事件去调用采用两种方式去移动精灵键盘事件和鼠标事件使用键盘事件的时候我们需要知道一个知识点我们采用分量概念去乘上速度来达到效果
Sprite.h中
public:Sprite() default;
Sprite(const QString fileName, const QSize size QSize());//接口
QVector2D getPos()const { return m_pos; }
QPixmap getPixmap()const { return m_image; }
QVector2D velocity() const{ return m_velocity; }
QVector2D velocity() { return m_velocity; }
private
//移动速度
float m_speed 3;
//速度分量
QVector2D m_velocity;
Sprite.cpp中 void Sprite::update() {//获取一下坐标float x m_pos.x();float y m_pos.y();//通过分量去改变坐标的速度移动就比较正常一点x m_velocity.x() * m_speed;y m_velocity.y() * m_speed;//将坐标给m_posm_pos { x,y }; }QGame.h protected:void paintEvent(QPaintEvent* ev) override;void keyPressEvent(QKeyEvent* ev) override;void keyReleaseEvent(QKeyEvent* ev) override;void mouseMoveEvent(QMouseEvent* ev) override;QGame.cpp //捕获按键事件 void QGame::keyPressEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:player-velocity().setY(-1);break;case Qt::Key_Down:player-velocity().setY(1);break;case Qt::Key_Left:player-velocity().setX(-1);break;case Qt::Key_Right:player-velocity().setX(1);break;} }void QGame::keyReleaseEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:case Qt::Key_Down:player-velocity().setY(0);break;case Qt::Key_Left:case Qt::Key_Right:player-velocity().setX(0);break;} }void QGame::mouseMoveEvent(QMouseEvent* ev) {//让鼠标居中到图片中间auto pos player-sizeImage() / 2;player-setPos(ev-pos() - QPoint{ pos.width(),pos.height() }); }子弹类飞机类与单例设计模式 构造两个类一个子弹类一个飞机类为了在这些类里面能使用QGame的实例我们设计一个单例设计模式让QGame实例唯一存在 QGame.h #ifndef QGAMEH #define QGAMEH #include QWidget #include Qtimer //宏定义一下这个单例 #define qGame QGame::instance()class QGame :public QWidget {Q_OBJECT public://单例设计模式,让QGame实例只允许存在一个static QGame* instance();QGame(QWidget* parent nullptr);~QGame();//游戏初始化void init(const QSize size, const QString title);//游戏反初始化void clean();//更新游戏站位符与父类的方法做区别void update(int);//渲染游戏void render(QPainter* painter);//游戏是否进行bool isRuning() const;//退出游戏void quit();//运行游戏void runGame();//设置游戏帧率void setFps(qreal fps);//获取游戏帧数的接口qreal fps() const { return m_fps; } protected:void paintEvent(QPaintEvent* ev) override;void keyPressEvent(QKeyEvent* ev) override;void keyReleaseEvent(QKeyEvent* ev) override;void mouseMoveEvent(QMouseEvent* ev) override; private://控制游戏进行的变量bool m_isRunning false;//游戏的主循环QTimer* m_mainLoopTimer{};//游戏帧率60帧qreal m_fps 1000 / 60; };#endifQGame.cpp #include QGame.h #include Sprite.h #include QApplication #include QPainter #include QKeyEvent #include QMessageBox//定义一个静态指针指向唯一对象 static QGame* ins nullptr; QGame* QGame::instance() {return ins; }QGame::QGame(QWidget* parent) :QWidget(parent), m_mainLoopTimer(new QTimer) {//保证不存在调用多个QGame实例Q_ASSERT_X(ins nullptr, QGame, 已经存在一个QGame实例);ins this; } QGame::~QGame() {//清理clean(); }//全局精灵类,注意这里必须使用指针类如果是普通类对象会报错 //因为QT里面QApplication执行后是不允许对象还没有构造完的指针是个不完整类就不会默认构造 Sprite* player;//游戏初始化 void QGame::init(const QSize size, const QString title) {//设置窗口固定大小setFixedSize(size);//设置标题setWindowTitle(title);//开启鼠标自动追踪setMouseTracking(true);player new Sprite;player-setPixmap(:/plane/Resource/images/hero1.png);//因为上面会有各种资源的初始化如果初始化失败那么m_isRunningfalse;游戏不继续运行了//初始化成功就为true m_isRunning true; } //游戏反初始化 void QGame::clean() { } //更新游戏 void QGame::update(int) {player-update(); } //渲染游戏 void QGame::render(QPainter* painter) {player-render(painter); } //游戏是否进行 bool QGame::isRuning() const {return true; } //退出游戏 void QGame::quit() {m_isRunning false; } //运行游戏 void QGame::runGame() { //显示窗口show();//连接定时器m_mainLoopTimer-callOnTimeout({//如果游戏没有在运行那么就结束游戏if (!isRuning()){m_mainLoopTimer-stop();qApp-quit();}//更新游戏,QGame的自定义updateupdate(0);//重绘,父类的updateQWidget::update();//测试游戏是否在进行qDebug() 游戏运行中;});//开始定时器设置游戏开启的帧数m_mainLoopTimer-start(m_fps); } //设置游戏帧率 void QGame::setFps(qreal fps) {m_fps fps; }//绘图事件 void QGame::paintEvent(QPaintEvent* ev) {//开启画家QPainter painter(this);//渲染游戏render(painter); }//捕获按键事件 void QGame::keyPressEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:player-velocity().setY(-1);break;case Qt::Key_Down:player-velocity().setY(1);break;case Qt::Key_Left:player-velocity().setX(-1);break;case Qt::Key_Right:player-velocity().setX(1);break;} }void QGame::keyReleaseEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:case Qt::Key_Down:player-velocity().setY(0);break;case Qt::Key_Left:case Qt::Key_Right:player-velocity().setX(0);break;} }void QGame::mouseMoveEvent(QMouseEvent* ev) {//让鼠标居中到图片中间auto pos player-sizeImage() / 2;player-setPos(ev-pos() - QPoint{ pos.width(),pos.height() }); }PlayerPlane.h #ifndef PLAYERPLANEH #define PLAYERPLANEH#include Sprite.h #include Bullet.h #include array class PlayerPlane : public Sprite { public:PlayerPlane();//发射子弹bool emitBullet(); private:}; #endif // !PLAYERPLANE_H_PlayerPlane.cpp #include PlayerPlane.hPlayerPlane::PlayerPlane() {}bool PlayerPlane::emitBullet() {return false; }Bullte.h #ifndef BULLETH #define BULLETH#include Sprite.h class Bullet :public Sprite { public://更新子弹出边界就得消失void update() override; private:}; #endif // !BULLET_H_Bullte.cpp #include Bullet.h #include QGame.h void Bullet::update() {//父类方法帮忙移动Sprite::update();//就可以调用游戏唯一的单例//如果子弹超出边界让子弹消失if (getPos().x() qGame-width() || getPos().x() 0 - sizeImage().width() ||getPos().y() qGame-height() || getPos().y() 0 - sizeImage().height()){destroy();} } 精灵管理类 创建一个EntityManager类来管理所有的实体与精灵为这个类构造单例然后使用链表去管理存储所有的实体与精灵。主游戏里面的所有实体与精灵就可以通过EntityManger这个单例去完成操作 EntityManager.h #ifndef ENTITYMANAGERH #define ENTITYMANAGERH#includeSprite.h #includeQList #includememory #includeQDebug class EntityManager { public://得到唯一的实例static EntityManager instance(){static EntityManager ev;return ev;}//更新管理的所有实体与精灵void update(){for (auto e : m_entities){e-update();}}//渲染void render(QPainter* painter){for (auto e : m_entities){e-render(painter);}}//添加实体开个模版方便使用templatetypename T EntityT* addEntity(T* e){m_entities.emplaceBack(e);return e;}//刷新如果有实体要消除就在这里销毁void refresh(){m_entities.removeIf({if (!e-active()){//测试输出qDebug() destoryed e;//释放这个实体delete e;return true;}return false;});//测试输出qDebug() m_entities.size();}private:QListEntity* m_entities;//构造函数私有化设计单例EntityManager() {} }; #endif PlayerPlane.h #ifndef PLAYERPLANEH #define PLAYERPLANEH#include Sprite.h #include Bullet.h #include array class PlayerPlane : public Sprite { public://继承父类的构造方法using Sprite::Sprite;PlayerPlane();//发射子弹bool emitBullet(); private:}; #endif // !PLAYERPLANE_H_此时的PlayerPlane.cpp就可以处理发射子弹了 #include PlayerPlane.h #include EntityManager.h PlayerPlane::PlayerPlane() {}bool PlayerPlane::emitBullet() {Bullet* b new Bullet;//添加子弹b-setPixmap(:/plane/Resource/images/bullet2.png);//设置子弹在主角上b-setPos(getPos() QVector2D{ sizeImage().width() / 2.0f,0.0f });//子弹发出b-velocity().setY(-1);//添加进实体EntityManager::instance().addEntity(b);return false; } QGame.cpp #include QGame.h #include Sprite.h #include EntityManager.h #include PlayerPlane.h#include QApplication #include QPainter #include QKeyEvent #include QMessageBox//定义一个静态指针指向唯一对象 static QGame* ins nullptr; QGame* QGame::instance() {return ins; }QGame::QGame(QWidget* parent) :QWidget(parent), m_mainLoopTimer(new QTimer) {//保证不存在调用多个QGame实例Q_ASSERT_X(ins nullptr, QGame, 已经存在一个QGame实例);ins this; } QGame::~QGame() {//清理clean(); }//全局精灵类,注意这里必须使用指针类如果是普通类对象会报错 //因为QT里面QApplication执行后是不允许对象还没有构造完的指针是个不完整类就不会默认构造 PlayerPlane* player;//游戏初始化 void QGame::init(const QSize size, const QString title) {//设置窗口固定大小setFixedSize(size);//设置标题setWindowTitle(title);//开启鼠标自动追踪setMouseTracking(true);player EntityManager::instance().addEntity(new PlayerPlane(:/plane/Resource/images/hero1.png));//因为上面会有各种资源的初始化如果初始化失败那么m_isRunningfalse;游戏不继续运行了//初始化成功就为true m_isRunning true; } //游戏反初始化 void QGame::clean() { } //更新游戏 void QGame::update(int) {//刷新销毁所有不需要的实体精灵EntityManager::instance().refresh();//更新实体精灵信息EntityManager::instance().update();//发射子弹player-emitBullet(); } //渲染游戏 void QGame::render(QPainter* painter) {EntityManager::instance().render(painter); } //游戏是否进行 bool QGame::isRuning() const {return true; } //退出游戏 void QGame::quit() {m_isRunning false; } //运行游戏 void QGame::runGame() { //显示窗口show();//连接定时器m_mainLoopTimer-callOnTimeout({//如果游戏没有在运行那么就结束游戏if (!isRuning()){m_mainLoopTimer-stop();qApp-quit();}//更新游戏,QGame的自定义updateupdate(0);//重绘,父类的updateQWidget::update();//测试游戏是否在进行//qDebug() 游戏运行中;});//开始定时器设置游戏开启的帧数m_mainLoopTimer-start(m_fps); } //设置游戏帧率 void QGame::setFps(qreal fps) {m_fps fps; }//绘图事件 void QGame::paintEvent(QPaintEvent* ev) {//开启画家QPainter painter(this);//渲染游戏render(painter); }//捕获按键事件 void QGame::keyPressEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:player-velocity().setY(-1);break;case Qt::Key_Down:player-velocity().setY(1);break;case Qt::Key_Left:player-velocity().setX(-1);break;case Qt::Key_Right:player-velocity().setX(1);break;} }void QGame::keyReleaseEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:case Qt::Key_Down:player-velocity().setY(0);break;case Qt::Key_Left:case Qt::Key_Right:player-velocity().setX(0);break;} }void QGame::mouseMoveEvent(QMouseEvent* ev) {//让鼠标居中到图片中间auto pos player-sizeImage() / 2;player-setPos(ev-pos() - QPoint{ pos.width(),pos.height() }); } 背景图滚动 思路因为沿着y轴移动用两个变量来表示图片不同位置的y坐标然后一个位置在窗口上一个位置在窗口上方让两个变量一直自增实现滚动像素当窗口上的坐标大于窗口高度时就把窗口上的y坐标重置为0当窗口之上的坐标大于0时就把y坐标重置为一开始的窗口之上的坐标 Map::Map() {//加载背景图m_pixmap.load(:/plane/Resource/images/background.png);//一个在窗口上面yPos1 -m_pixmap.height();//一个在窗口上yPos2 0; } void Map::update() {//实现滚动背景yPos1 m_scrollSpeed;if (yPos1 0){yPos1 -m_pixmap.height();}yPos2 m_scrollSpeed;//大于等于窗口高度后重新置为0if (yPos2 qGame-height()){yPos2 0;} } void Map::render(QPainter* painter) {painter-drawPixmap(0, yPos1, m_pixmap);painter-drawPixmap(0, yPos2, m_pixmap); }新建地图类继承实体类然后去重写渲染与更新方法 Map.h #ifndef MAPH #define MAPH#include Entity.h class Map :public Entity { public:Map();// 通过 Entity 继承virtual void update() override;virtual void render(QPainter* painter) override; private:QPixmap m_pixmap;//用来实现滚动int yPos1,yPos2;int m_scrollSpeed 2; }; #endif // !MAPH Map.cpp #include Map.h #include QGame.h Map::Map() {//加载背景图m_pixmap.load(:/plane/Resource/images/background.png);//一个在窗口上面yPos1 -m_pixmap.height();//一个在窗口上yPos2 0; }void Map::update() {//实现滚动背景yPos1 m_scrollSpeed;if (yPos1 0){yPos1 -m_pixmap.height();}yPos2 m_scrollSpeed;//大于等于窗口高度后重新置为0if (yPos2 qGame-height()){yPos2 0;} }void Map::render(QPainter* painter) {painter-drawPixmap(0, yPos1, m_pixmap);painter-drawPixmap(0, yPos2, m_pixmap); }子弹与敌机碰撞 新建一个类用来存放应该enumenum里面存放不同类别标识现在就需要在子弹player敌机生成的时候设置类别方便后面进行碰撞判断在EntityManager中提供类别识别方法注意识别类型要是活动的不然就没意义在Sprite中构造矩阵变量在update方法中添加矩阵的构造采用矩阵碰撞方式去检测碰撞最后在QGame.cpp中去完成敌机的生成与碰撞。基本完整框架如下 main.cpp #include QApplication #include QGame.hint main(int argc,char* argv[]) {QApplication a(argc, argv);QGame game;game.init({ 480,852 }, 小瓜);game.runGame();return a.exec(); }QGame.h #ifndef QGAMEH #define QGAMEH #include QWidget #include Qtimer //宏定义一下这个单例 #define qGame QGame::instance()class QGame :public QWidget {Q_OBJECT public://单例设计模式,让QGame实例只允许存在一个static QGame* instance();QGame(QWidget* parent nullptr);~QGame();//游戏初始化void init(const QSize size, const QString title);//游戏反初始化void clean();//更新游戏站位符与父类的方法做区别void update(int);//渲染游戏void render(QPainter* painter);//游戏是否进行bool isRuning() const;//退出游戏void quit();//运行游戏void runGame();//设置游戏帧率void setFps(qreal fps);//获取游戏帧数的接口qreal fps() const { return m_fps; } protected:void paintEvent(QPaintEvent* ev) override;void keyPressEvent(QKeyEvent* ev) override;void keyReleaseEvent(QKeyEvent* ev) override;void mouseMoveEvent(QMouseEvent* ev) override; private://控制游戏进行的变量bool m_isRunning false;//游戏的主循环QTimer* m_mainLoopTimer{};//游戏帧率60帧qreal m_fps 1000 / 60; };#endifQGame.cpp #include QGame.h #include Sprite.h #include EntityManager.h #include PlayerPlane.h #include Map.h#include QApplication #include QPainter #include QKeyEvent #include QMessageBox #include QStringList //随机数头文件 #include qrandom.h//宏定义这个随机生成器函数 #define qRand(min,max) QRandomGenerator::global()-bounded(min, max)//定义一个静态指针指向唯一对象 static QGame* ins nullptr; QGame* QGame::instance() {return ins; }QGame::QGame(QWidget* parent) :QWidget(parent), m_mainLoopTimer(new QTimer) {//保证不存在调用多个QGame实例Q_ASSERT_X(ins nullptr, QGame, 已经存在一个QGame实例);ins this; } QGame::~QGame() {//清理clean(); }//全局精灵类,注意这里必须使用指针类如果是普通类对象会报错 //因为QT里面QApplication执行后是不允许对象还没有构造完的指针是个不完整类就不会默认构造 PlayerPlane* player;//游戏初始化 void QGame::init(const QSize size, const QString title) {//设置窗口固定大小setFixedSize(size);//设置标题setWindowTitle(title);//开启鼠标自动追踪setMouseTracking(true);//初始化背景EntityManager::instance().addEntity(new Map);//初始化主角对象player EntityManager::instance().addEntity(new PlayerPlane(:/plane/Resource/images/hero1.png));player-setType(Player);//因为上面会有各种资源的初始化如果初始化失败那么m_isRunningfalse;游戏不继续运行了//初始化成功就为true m_isRunning true; } //游戏反初始化 void QGame::clean() { } //更新游戏 void QGame::update(int) {//刷新销毁所有不需要的实体精灵EntityManager::instance().refresh();//更新实体精灵信息EntityManager::instance().update();static int BulletVelocity 0;//发射子弹的速率if (BulletVelocity % 10 0){//发射子弹player-emitBullet();}//出现敌机if (BulletVelocity % 60 0){QStringList efile { :/plane/Resource/images/enemy1.png,:/plane/Resource/images/enemy2.png };auto enemy new Sprite(efile[qRand(0,2)]);//设置敌机从上面往下enemy-velocity().setY(1);//设置随机出现的敌机位置enemy-setPos(qRand(0, width()), -50);//设置类别enemy-setType(Enemy);//添加到精灵管理类中EntityManager::instance().addEntity(enemy);}//获取子弹列表auto bullet_list EntityManager::instance().getSpriteByType(bullet);//获取敌机列表auto enemy_list EntityManager::instance().getSpriteByType(Enemy);//遍历查看是否矩形碰撞for (auto e : enemy_list){for (auto b : bullet_list){//判断敌机是否包含子弹如果包含就释放掉子弹和敌机if (e-collider().intersects(b-collider())){e-destroy();b-destroy();break;}}}BulletVelocity;qDebug() 时间值 BulletVelocity; } //渲染游戏 void QGame::render(QPainter* painter) {EntityManager::instance().render(painter); } //游戏是否进行 bool QGame::isRuning() const {return true; } //退出游戏 void QGame::quit() {m_isRunning false; } //运行游戏 void QGame::runGame() { //显示窗口show();//连接定时器m_mainLoopTimer-callOnTimeout({//如果游戏没有在运行那么就结束游戏if (!isRuning()){m_mainLoopTimer-stop();qApp-quit();}//更新游戏,QGame的自定义updateupdate(0);//重绘,父类的updateQWidget::update();//测试游戏是否在进行//qDebug() 游戏运行中;});//开始定时器设置游戏开启的帧数m_mainLoopTimer-start(m_fps); } //设置游戏帧率 void QGame::setFps(qreal fps) {m_fps fps; }//绘图事件 void QGame::paintEvent(QPaintEvent* ev) {//开启画家QPainter painter(this);//渲染游戏render(painter); }//捕获按键事件 void QGame::keyPressEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:player-velocity().setY(-1);break;case Qt::Key_Down:player-velocity().setY(1);break;case Qt::Key_Left:player-velocity().setX(-1);break;case Qt::Key_Right:player-velocity().setX(1);break;} }void QGame::keyReleaseEvent(QKeyEvent* ev) {switch (ev-key()){case Qt::Key_Up:case Qt::Key_Down:player-velocity().setY(0);break;case Qt::Key_Left:case Qt::Key_Right:player-velocity().setX(0);break;} }void QGame::mouseMoveEvent(QMouseEvent* ev) {//让鼠标居中到图片中间auto pos player-sizeImage() / 2;player-setPos(ev-pos() - QPoint{ pos.width(),pos.height() }); }Entity.h #ifndef ENTITYH #define ENTITYH#include Global.h #include QPainterclass Entity { public:virtual ~Entity() {};//虚析构当子类继承重写的时候就可以释放子类的内存virtual void update() 0;//更新实体virtual void render(QPainter* painter) 0;//渲染实体//接口bool active()const { return m_active; }int type()const { return m_type; }//状态销毁void destroy() { m_active false; }//设置实体类型void setType(int type) { m_type type; } private:bool m_active true;//实体是否是活动的int m_type 0;//实体类型}; #endif // !ENTITY_H_Sprite.h #ifndef SPRITEH #define SPRITEH#include Entity.h #include QVector2Dclass Sprite :public Entity { public:Sprite() default;Sprite(const QString fileName, const QSize size QSize());//接口QVector2D getPos()const { return m_pos; }QPixmap getPixmap()const { return m_image; }QVector2D velocity() const{ return m_velocity; }QVector2D velocity() { return m_velocity; }QRect collider()const { return m_collider; }//设置坐标void setPos(float x, float y){m_pos { x,y };}void setPos(const QPointF pos){m_pos { (float)pos.x(),(float)pos.y() };}void setPos(const QVector2D pos) {m_pos pos; }//设置速度分量void setVelocity(float vx, float vy){m_velocity { vx,vy };}//获取图片大小QSize sizeImage()const;//设置图片void setPixmap(const QString fileName, const QSize size QSize());// 通过 Entity 继承void update() override;// 通过 Entity 继承void render(QPainter* painter) override;private:QPixmap m_image;QVector2D m_pos;//移动速度float m_speed 3;//速度分量QVector2D m_velocity;//碰撞器QRect m_collider{}; }; #endif // !SPRITEH Sprite.cpp #include Sprite.hSprite::Sprite(const QString fileName, const QSize size) {setPixmap(fileName, size); }//获取精灵图片大小 QSize Sprite::sizeImage() const {if (m_image.isNull()){return QSize();}return m_image.size(); } //设置图片 void Sprite::setPixmap(const QString fileName, const QSize size) {m_image.load(fileName);if (size.isValid()){//保持缩放 m_image.scaled(size, Qt::AspectRatioMode::KeepAspectRatio);} }void Sprite::update() {//获取一下坐标float x m_pos.x();float y m_pos.y();//通过分量去改变坐标的速度移动就比较正常一点x m_velocity.x() * m_speed;y m_velocity.y() * m_speed;//将坐标给m_posm_pos { x,y };//设置矩形m_collider QRect(m_pos.x(), m_pos.y(), m_image.width(), m_image.height()); }void Sprite::render(QPainter* painter) {painter-drawPixmap(m_pos.toPoint(), m_image); }Bullet.h #ifndef BULLETH #define BULLETH#include Sprite.h class Bullet :public Sprite { public://更新子弹出边界就得消失void update() override; private:}; #endif // !BULLETH Bullet.cpp #include Bullet.h #include QGame.h void Bullet::update() {//继承父类的方法帮忙移动Sprite::update();//就可以调用游戏唯一的单例//如果子弹超出边界让子弹消失if (getPos().x() qGame-width() || getPos().x() 0 - sizeImage().width() ||getPos().y() qGame-height() || getPos().y() 0 - sizeImage().height()){destroy();} }PlayerPlane.h #ifndef PLAYERPLANEH #define PLAYERPLANEH#include Sprite.h #include Bullet.h #include array class PlayerPlane : public Sprite { public://继承父类的构造方法using Sprite::Sprite;PlayerPlane();//发射子弹bool emitBullet(); private:}; #endif // !PLAYERPLANEH PlayerPlane.cpp #include PlayerPlane.h #include EntityManager.h PlayerPlane::PlayerPlane() {}bool PlayerPlane::emitBullet() {Bullet* b new Bullet;//添加子弹b-setPixmap(:/plane/Resource/images/bullet2.png);//设置子弹在主角上b-setPos(getPos() QVector2D{ sizeImage().width() / 2.0f,0.0f });//子弹发出b-velocity().setY(-2);//设置类型b-setType(bullet);//添加进实体EntityManager::instance().addEntity(b);return false; }EntityManager.h #ifndef ENTITYMANAGERH #define ENTITYMANAGERH#includeSprite.h #includeQList #includememory #includeQDebug class EntityManager { public://得到唯一的实例static EntityManager instance(){static EntityManager ev;return ev;}//更新管理的所有实体与精灵void update(){for (auto e : m_entities){e-update();}}//渲染void render(QPainter* painter){for (auto e : m_entities){e-render(painter);}}//添加实体开个模版方便使用templatetypename T EntityT* addEntity(T* e){m_entities.emplaceBack(e);return e;}//刷新如果有实体要消除就在这里销毁void refresh(){m_entities.removeIf({//不是活动的就释放if (!e-active()){//测试输出qDebug() destoryed e;//释放这个实体delete e;return true;}return false;});//测试输出qDebug() m_entities.size();}//获取类别好做碰撞QListSprite* getSpriteByType(int type){QListSprite* s;for (auto e : m_entities){//要是活动的if(e-type()type e-active()){s.append(dynamic_castSprite(e));}}return s;} private:QListEntity m_entities;//构造函数私有化设计单例EntityManager() {} };#endifMap.h #ifndef MAPH #define MAPH#include Entity.h class Map :public Entity { public:Map();// 通过 Entity 继承virtual void update() override;virtual void render(QPainter* painter) override; private:QPixmap m_pixmap;//用来实现滚动int yPos1,yPos2;int m_scrollSpeed 2; }; #endif // !MAPH Map.cpp #include Map.h #include QGame.h Map::Map() {//加载背景图m_pixmap.load(:/plane/Resource/images/background.png);//一个在窗口上面yPos1 -m_pixmap.height();//一个在窗口上yPos2 0; }void Map::update() {//实现滚动背景yPos1 m_scrollSpeed;if (yPos1 0){yPos1 -m_pixmap.height();}yPos2 m_scrollSpeed;//大于等于窗口高度后重新置为0if (yPos2 qGame-height()){yPos2 0;} }void Map::render(QPainter* painter) {painter-drawPixmap(0, yPos1, m_pixmap);painter-drawPixmap(0, yPos2, m_pixmap); } Global.h #ifndef GLOBALH #define GLOBAL_H_enum EntityType {None,Player,Enemy,bullet };#endif运行结果
相关文章
-
我想做个网站怎么做 找谁做好山东省城乡与住房建设厅网站
我想做个网站怎么做 找谁做好山东省城乡与住房建设厅网站
- 技术栈
- 2026年04月20日
-
我想自己开发一个游戏seo排名赚app最新版本
我想自己开发一个游戏seo排名赚app最新版本
- 技术栈
- 2026年04月20日
-
我想自己建立一个网站昆明制作网站公司
我想自己建立一个网站昆明制作网站公司
- 技术栈
- 2026年04月20日
-
我需要网站网站能需要怎么做才不会被攻击
我需要网站网站能需要怎么做才不会被攻击
- 技术栈
- 2026年04月20日
-
我也来做外国网站购物vx小程序怎么制作
我也来做外国网站购物vx小程序怎么制作
- 技术栈
- 2026年04月20日
-
我用帝国做的网站上传到别一个服务器上重新邦了一个域名平面设计师招聘网
我用帝国做的网站上传到别一个服务器上重新邦了一个域名平面设计师招聘网
- 技术栈
- 2026年04月20日
