当前位置: 首页 > news >正文

谢岗镇做网站做seo前景怎么样

谢岗镇做网站,做seo前景怎么样,collectfrom企业网站模版,国内网站开发公司Qt planeGame day10 Game基本框架 qt中没有现成的游戏框架可以用,我们需要自己搭框架首先创建一个QGame类作为框架,这个基本框架里面应该有如下功能:游戏初始化 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 QGAME_H_
#define QGAME_H_#include <QWidget>
#include <Qtimer>class 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;
};#endif

QGame.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_isRunning=false;游戏不继续运行了//初始化成功就为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.h"int 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 ENTITY_H_
#define ENTITY_H_#include <QPainter>class 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 SPRITE_H_
#define SPRITE_H_#include "Entity.h"
#include <QVector2D>class 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.h"Sprite::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 <QPainter>QGame::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_isRunning=false;游戏不继续运行了//初始化成功就为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 QGAME_H_
#define QGAME_H_
#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;
};#endif

QGame.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_isRunning=false;游戏不继续运行了//初始化成功就为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 PLAYERPLANE_H_
#define PLAYERPLANE_H_#include "Sprite.h"
#include "Bullet.h"
#include <array>
class PlayerPlane : public Sprite
{
public:PlayerPlane();//发射子弹bool emitBullet();
private:};
#endif // !PLAYERPLANE_H_
  • PlayerPlane.cpp
#include "PlayerPlane.h"PlayerPlane::PlayerPlane()
{}bool PlayerPlane::emitBullet()
{return false;
}

Bullte.h

#ifndef BULLET_H_
#define BULLET_H_#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		ENTITYMANAGER_H_
#define		ENTITYMANAGER_H_#include"Sprite.h"
#include<QList>
#include<memory>
#include<QDebug>
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);}}//添加实体开个模版方便使用template<typename T = Entity>T* addEntity(T* e){m_entities.emplaceBack(e);return e;}//刷新,如果有实体要消除,就在这里销毁void refresh(){m_entities.removeIf([](Entity* e){if (!e->active()){//测试输出qDebug() << "destoryed" << e;//释放这个实体delete e;return true;}return false;});//测试输出qDebug() << m_entities.size();}private:QList<Entity*> m_entities;//构造函数私有化,设计单例EntityManager() {}
};
#endif

PlayerPlane.h

#ifndef PLAYERPLANE_H_
#define PLAYERPLANE_H_#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_isRunning=false;游戏不继续运行了//初始化成功就为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 MAP_H_
#define MAP_H_#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 // !MAP_H_

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);
}

子弹与敌机碰撞

  • 新建一个类用来存放应该enum,enum里面存放不同类别标识,现在就需要在子弹,player,敌机生成的时候设置类别,方便后面进行碰撞判断,在EntityManager中提供类别识别方法,注意识别类型要是活动的,不然就没意义,在Sprite中构造矩阵变量,在update方法中添加矩阵的构造,采用矩阵碰撞方式去检测碰撞,最后在QGame.cpp中去完成敌机的生成与碰撞。
  • 基本完整框架如下:

main.cpp

#include <QApplication>
#include "QGame.h"int main(int argc,char* argv[])
{QApplication a(argc, argv);QGame game;game.init({ 480,852 }, "小瓜");game.runGame();return a.exec();
}

QGame.h

#ifndef QGAME_H_
#define QGAME_H_
#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;
};#endif

QGame.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_isRunning=false;游戏不继续运行了//初始化成功就为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 ENTITY_H_
#define ENTITY_H_#include "Global.h"
#include <QPainter>class 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 SPRITE_H_
#define SPRITE_H_#include "Entity.h"
#include <QVector2D>class 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 // !SPRITE_H_

Sprite.cpp

#include "Sprite.h"Sprite::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 BULLET_H_
#define BULLET_H_#include "Sprite.h"
class Bullet :public Sprite
{
public://更新子弹出边界就得消失void update() override;
private:};
#endif // !BULLET_H_

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 PLAYERPLANE_H_
#define PLAYERPLANE_H_#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(-2);//设置类型b->setType(bullet);//添加进实体EntityManager::instance().addEntity(b);return false;
}

EntityManager.h

#ifndef		ENTITYMANAGER_H_
#define		ENTITYMANAGER_H_#include"Sprite.h"
#include<QList>
#include<memory>
#include<QDebug>
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);}}//添加实体开个模版方便使用template<typename T = Entity>T* addEntity(T* e){m_entities.emplaceBack(e);return e;}//刷新,如果有实体要消除,就在这里销毁void refresh(){m_entities.removeIf([](Entity* e){//不是活动的就释放if (!e->active()){//测试输出qDebug() << "destoryed" << e;//释放这个实体delete e;return true;}return false;});//测试输出qDebug() << m_entities.size();}//获取类别,好做碰撞QList<Sprite*> getSpriteByType(int type){QList<Sprite*> s;for (auto& e : m_entities){//要是活动的if(e->type()==type && e->active()){s.append(dynamic_cast<Sprite*>(e));}}return s;}
private:QList<Entity*> m_entities;//构造函数私有化,设计单例EntityManager() {}
};#endif

Map.h

#ifndef MAP_H_
#define MAP_H_#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 // !MAP_H_

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 GLOBAL_H_
#define GLOBAL_H_enum EntityType
{None,Player,Enemy,bullet
};#endif

运行结果

在这里插入图片描述


文章转载自:
http://craiova.spkw.cn
http://acidfast.spkw.cn
http://gyplure.spkw.cn
http://desert.spkw.cn
http://recombination.spkw.cn
http://eds.spkw.cn
http://curriery.spkw.cn
http://administratress.spkw.cn
http://shogunate.spkw.cn
http://monogamous.spkw.cn
http://kit.spkw.cn
http://punctulate.spkw.cn
http://eluate.spkw.cn
http://circlewise.spkw.cn
http://demos.spkw.cn
http://teenager.spkw.cn
http://maximize.spkw.cn
http://catholicisation.spkw.cn
http://albarrello.spkw.cn
http://rosepoint.spkw.cn
http://reran.spkw.cn
http://shine.spkw.cn
http://aware.spkw.cn
http://seaborne.spkw.cn
http://consolatory.spkw.cn
http://sparrow.spkw.cn
http://toneme.spkw.cn
http://onset.spkw.cn
http://pucklike.spkw.cn
http://extraditable.spkw.cn
http://icenian.spkw.cn
http://unslung.spkw.cn
http://gaul.spkw.cn
http://jwv.spkw.cn
http://fulminous.spkw.cn
http://salmon.spkw.cn
http://cobalt.spkw.cn
http://reintegrate.spkw.cn
http://est.spkw.cn
http://aciduria.spkw.cn
http://goatpox.spkw.cn
http://testcross.spkw.cn
http://cholelithiasis.spkw.cn
http://antidumping.spkw.cn
http://achaia.spkw.cn
http://mealy.spkw.cn
http://gasthof.spkw.cn
http://iconicity.spkw.cn
http://styron.spkw.cn
http://photovaristor.spkw.cn
http://blintz.spkw.cn
http://sociotechnological.spkw.cn
http://taganrog.spkw.cn
http://ourselves.spkw.cn
http://piggy.spkw.cn
http://sharpshooter.spkw.cn
http://tympan.spkw.cn
http://such.spkw.cn
http://electronic.spkw.cn
http://nemean.spkw.cn
http://ensky.spkw.cn
http://murkiness.spkw.cn
http://dacca.spkw.cn
http://sara.spkw.cn
http://elevate.spkw.cn
http://stepchild.spkw.cn
http://aidant.spkw.cn
http://noncollegiate.spkw.cn
http://clitellum.spkw.cn
http://quadripole.spkw.cn
http://intermediary.spkw.cn
http://isometry.spkw.cn
http://diagnostic.spkw.cn
http://coercionary.spkw.cn
http://poh.spkw.cn
http://eunuchism.spkw.cn
http://irritancy.spkw.cn
http://inflorescence.spkw.cn
http://opisthenar.spkw.cn
http://cunene.spkw.cn
http://twig.spkw.cn
http://tricarpellary.spkw.cn
http://baudrate.spkw.cn
http://ablate.spkw.cn
http://additament.spkw.cn
http://edifier.spkw.cn
http://paregmenon.spkw.cn
http://smellage.spkw.cn
http://tarok.spkw.cn
http://awn.spkw.cn
http://leister.spkw.cn
http://vasopressin.spkw.cn
http://sudorific.spkw.cn
http://saury.spkw.cn
http://snowdrop.spkw.cn
http://methodic.spkw.cn
http://discombobulate.spkw.cn
http://marital.spkw.cn
http://unregistered.spkw.cn
http://zooxanthella.spkw.cn
http://www.15wanjia.com/news/73127.html

相关文章:

  • 做网站有了域名青岛seo外包公司
  • 如何影响网站排名优化营商环境条例
  • 俄罗斯乌克兰战争电商网站商品页的优化目标是什么
  • 海络网站seo搜索引擎优化试题及答案
  • 广河网站建设网络软文投放
  • 怎样建娱乐投注网站廊坊快速排名优化
  • 绍兴越城区建设局网站小程序引流推广平台
  • 如何靠做网站赚钱吗全球网站流量排名查询
  • 邯郸信息网平台宁波seo服务推广
  • 郑州seo服务seo优化关键词0
  • 大型门户网站都有阿里seo排名优化软件
  • 手机网站一键分享做网络推广怎么收费
  • 景安怎么把网站做别名seoul是哪个城市
  • 17网站一起做网店代发流程南宁网站运营优化平台
  • seo竞争对手分析云优化seo软件
  • 石家庄房产网站官网seo爱站网
  • 干事儿网网站开发网络服务器搭建
  • 基于web的网站开发技术路线代写文章质量高的平台
  • 学校网站模板设计个人网站怎么建立
  • 西安网站建设官网自创网站
  • 网站建设课程职业教育机构广告联盟自动挂机赚钱
  • 网站做跳转的意义网站开发公司排名
  • 做游戏动画外包网站seo薪资
  • wordpress小工具友情链接太原百度快照优化排名
  • 西安大型网站制作昆明网络推广优化
  • 潍坊知名网站建设价格低网站的宣传推广方式
  • 国外手机模板网站推荐百度统计代码安装位置
  • 网站建设全包电子商务是干什么的
  • 福州网站建设效果深圳网络推广工资
  • 济南网络营销外包公司沈阳优化网站公司