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{};
qreal m_fps = 1000 / 60;
- 基本框架思路:判断游戏是否运行中,运行中的话需要连接定时器处理游戏更新于绘图,然后开启定时器,因为qt的绘图只能在事件中完成,所以把渲染写在事件中即可,在定时器中去调用父类的更新画面
- 基本框架
QGame.h
#ifndef QGAME_H_
#define QGAME_H_
#include
#include
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{};
qreal m_fps = 1000 / 60;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
QGame.cpp
#include "QGame.h"
#include
#include
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 = 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();
}
update(0);
QWidget::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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
mian.cpp
#include
#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
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
精灵类
- 新建一个精灵类,这个类需要重写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
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());
void update() override;
void render(QPainter* painter) override;
private:
QPixmap m_image;
QVector2D m_pos;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
QGame.cpp
- 在QGame.cpp中声明一个全局的精灵类,然后去初始化精灵
#include "QGame.h"
#include "Sprite.h"
#include
#include
QGame::QGame(QWidget* parent) :QWidget(parent)
, m_mainLoopTimer(new QTimer)
{
}
QGame::~QGame()
{
clean();
}
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 = 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();
}
update(0);
QWidget::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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 运行结果

精灵移动
- 毫无疑问,我们需要让精灵动起来,那肯定得使用事件去调用,采用两种方式去移动精灵,键盘事件和鼠标事件
- 使用键盘事件的时候,我们需要知道一个知识点,我们采用分量概念去乘上速度来达到效果
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_pos = { x,y };
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
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() });
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
子弹类,飞机类与单例设计模式
- 构造两个类,一个子弹类一个飞机类,为了在这些类里面能使用QGame的实例,我们设计一个单例设计模式让QGame实例唯一存在
QGame.h
#ifndef QGAME_H_
#define QGAME_H_
#include
#include
#define qGame QGame::instance()
class QGame :public QWidget
{
Q_OBJECT
public:
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{};
qreal m_fps = 1000 / 60;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
QGame.cpp
#include "QGame.h"
#include "Sprite.h"
#include
#include
#include
#include
static QGame* ins = nullptr;
QGame* QGame::instance()
{
return ins;
}
QGame::QGame(QWidget* parent) :QWidget(parent)
, m_mainLoopTimer(new QTimer)
{
Q_ASSERT_X(ins == nullptr, "QGame", "已经存在一个QGame实例");
ins = this;
}
QGame::~QGame()
{
clean();
}
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 = 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();
}
update(0);
QWidget::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() });
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
PlayerPlane.h
#ifndef PLAYERPLANE_H_
#define PLAYERPLANE_H_
#include "Sprite.h"
#include "Bullet.h"
#include
class PlayerPlane : public Sprite
{
public:
PlayerPlane();
bool emitBullet();
private:
};
#endif
#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
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
#include
#include
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
PlayerPlane.h
#ifndef PLAYERPLANE_H_
#define PLAYERPLANE_H_
#include "Sprite.h"
#include "Bullet.h"
#include
class PlayerPlane : public Sprite
{
public:
using Sprite::Sprite;
PlayerPlane();
bool emitBullet();
private:
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
此时的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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
QGame.cpp
#include "QGame.h"
#include "Sprite.h"
#include "EntityManager.h"
#include "PlayerPlane.h"
#include
#include
#include
#include
static QGame* ins = nullptr;
QGame* QGame::instance()
{
return ins;
}
QGame::QGame(QWidget* parent) :QWidget(parent)
, m_mainLoopTimer(new QTimer)
{
Q_ASSERT_X(ins == nullptr, "QGame", "已经存在一个QGame实例");
ins = this;
}
QGame::~QGame()
{
clean();
}
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 = 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();
}
update(0);
QWidget::update();
}
);
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() });
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
背景图滚动
- 思路:因为沿着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;
if (yPos2 >= qGame->height())
{
yPos2 = 0;
}
}
void Map::render(QPainter* painter)
{
painter->drawPixmap(0, yPos1, m_pixmap);
painter->drawPixmap(0, yPos2, m_pixmap);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
Map.h
#ifndef MAP_H_
#define MAP_H_
#include "Entity.h"
class Map :public Entity
{
public:
Map();
virtual void update() override;
virtual void render(QPainter* painter) override;
private:
QPixmap m_pixmap;
int yPos1,yPos2;
int m_scrollSpeed = 2;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
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;
if (yPos2 >= qGame->height())
{
yPos2 = 0;
}
}
void Map::render(QPainter* painter)
{
painter->drawPixmap(0, yPos1, m_pixmap);
painter->drawPixmap(0, yPos2, m_pixmap);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
子弹与敌机碰撞
- 新建一个类用来存放应该enum,enum里面存放不同类别标识,现在就需要在子弹,player,敌机生成的时候设置类别,方便后面进行碰撞判断,在EntityManager中提供类别识别方法,注意识别类型要是活动的,不然就没意义,在Sprite中构造矩阵变量,在update方法中添加矩阵的构造,采用矩阵碰撞方式去检测碰撞,最后在QGame.cpp中去完成敌机的生成与碰撞。
- 基本完整框架如下:
main.cpp
#include
#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
#include
#define qGame QGame::instance()
class QGame :public QWidget
{
Q_OBJECT
public:
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{};
qreal m_fps = 1000 / 60;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
QGame.cpp
#include "QGame.h"
#include "Sprite.h"
#include "EntityManager.h"
#include "PlayerPlane.h"
#include "Map.h"
#include
#include
#include
#include
#include
#include
#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)
{
Q_ASSERT_X(ins == nullptr, "QGame", "已经存在一个QGame实例");
ins = this;
}
QGame::~QGame()
{
clean();
}
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 = 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();
}
update(0);
QWidget::update();
}
);
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() });
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
Entity.h
#ifndef ENTITY_H_
#define ENTITY_H_
#include "Global.h"
#include
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
Sprite.h
#ifndef SPRITE_H_
#define SPRITE_H_
#include "Entity.h"
#include
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());
void update() override;
void render(QPainter* painter) override;
private:
QPixmap m_image;
QVector2D m_pos;
float m_speed = 3;
QVector2D m_velocity;
QRect m_collider{};
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
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_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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
Bullet.h
#ifndef BULLET_H_
#define BULLET_H_
#include "Sprite.h"
class Bullet :public Sprite
{
public:
void update() override;
private:
};
#endif
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
class PlayerPlane : public Sprite
{
public:
using Sprite::Sprite;
PlayerPlane();
bool emitBullet();
private:
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
EntityManager.h
#ifndef ENTITYMANAGER_H_
#define ENTITYMANAGER_H_
#include"Sprite.h"
#include
#include
#include
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
Map.h
#ifndef MAP_H_
#define MAP_H_
#include "Entity.h"
class Map :public Entity
{
public:
Map();
virtual void update() override;
virtual void render(QPainter* painter) override;
private:
QPixmap m_pixmap;
int yPos1,yPos2;
int m_scrollSpeed = 2;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
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;
if (yPos2 >= qGame->height())
{
yPos2 = 0;
}
}
void Map::render(QPainter* painter)
{
painter->drawPixmap(0, yPos1, m_pixmap);
painter->drawPixmap(0, yPos2, m_pixmap);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
Global.h
#ifndef GLOBAL_H_
#define GLOBAL_H_
enum EntityType
{
None,
Player,
Enemy,
bullet
};
#endif
运行结果

后续版
main.cpp
#include
#include "QGame.h"
#include "successWidget.h"
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
QGame game;
successWidget wid;
game.init({ 480,852 }, "小瓜");
game.runGame();
return a.exec();
}
#include "main.moc"
QGame.h
#ifndef QGAME_H_
#define QGAME_H_
#include "successWidget.h"
#include
#include
#include
#include
#define qGame QGame::instance()
class QGame :public QWidget
{
Q_OBJECT
public:
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{};
qreal m_fps = 1000 / 60;
successWidget* sWidget{};
int keySuccess = 0;
QLabel* Label = new QLabel("目标杀敌数:20", this);
QLabel* curLabel = new QLabel("当前杀敌人数:0", this);
char buff[256]{};
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
QGame.cpp
#include "QGame.h"
#include "Sprite.h"
#include "EntityManager.h"
#include "PlayerPlane.h"
#include "Map.h"
#include
#include
#include
#include
#include
#include
#define qRand(min,max) QRandomGenerator::global()->bounded(min, max)
#define successDate 20
static QGame* ins = nullptr;
QGame* QGame::instance()
{
return ins;
}
QGame::QGame(QWidget* parent) :QWidget(parent)
, m_mainLoopTimer(new QTimer)
, sWidget(new successWidget)
{
Q_ASSERT_X(ins == nullptr, "QGame", "已经存在一个QGame实例");
ins = this;
setWindowIcon(QIcon(":/plane/Resource/images/xiaogua.bmp"));
}
QGame::~QGame()
{
qDebug() << "QGame窗口结束";
clean();
}
PlayerPlane* player;
void QGame::init(const QSize& size, const QString& title)
{
setFixedSize(size);
setWindowTitle(title);
setMouseTracking(true);
EntityManager::instance().addEntity(new Map);
Label->setFont(QFont("宋体", 18));
Label->setGeometry(0, 0, 200, 50);
curLabel->setFont(QFont("宋体", 18));
curLabel->setGeometry(0, 50, 200, 50);
player = EntityManager::instance().addEntity(new PlayerPlane(":/plane/Resource/images/hero1.png"));
player->setType(Player);
player->setPos(200, 500);
m_isRunning = true;
}
void QGame::clean()
{
system("cls");
}
void QGame::update(int)
{
EntityManager::instance().refresh();
EntityManager::instance().update();
static int BulletVelocity = 0;
if (BulletVelocity % 10 == 0)
{
player->emitBullet();
}
if (BulletVelocity % 40 == 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();
keySuccess++;
sprintf(buff, "当前杀敌人数:%d", keySuccess);
curLabel->setText(buff);
break;
}
}
if (e->collider().intersects(player->collider()))
{
m_isRunning = false;
}
}
if (keySuccess == successDate)
{
m_isRunning = false;
}
BulletVelocity++;
if (BulletVelocity > 6000) BulletVelocity = 0;
}
void QGame::render(QPainter* painter)
{
EntityManager::instance().render(painter);
}
bool QGame::isRuning() const
{
return m_isRunning;
}
void QGame::quit()
{
m_isRunning = false;
}
void QGame::runGame()
{
show();
m_mainLoopTimer->callOnTimeout([=]()
{
if (!isRuning())
{
m_mainLoopTimer->stop();
instance()->hide();
if (keySuccess == successDate)
{
clean();
sWidget->show();
qDebug() << "小瓜:啧啧啧啧,太强了吧,这都被你过了,这场紧张又刺激的打飞机。";
}
else
{
clean();
qDebug() << "小瓜:你真菜,弱智游戏你都玩不过";
system("pause");
exit(0);
}
player->destroy();
}
update(0);
QWidget::update();
}
);
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() });
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
Entity.h
#ifndef ENTITY_H_
#define ENTITY_H_
#include "Global.h"
#include
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
Sprite.h
#ifndef SPRITE_H_
#define SPRITE_H_
#include "Entity.h"
#include
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());
void update() override;
void render(QPainter* painter) override;
private:
QPixmap m_image;
QVector2D m_pos;
float m_speed = 3;
QVector2D m_velocity;
QRect m_collider{};
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
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_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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
Bullet.h
#ifndef BULLET_H_
#define BULLET_H_
#include "Sprite.h"
class Bullet :public Sprite
{
public:
void update() override;
private:
};
#endif
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
class PlayerPlane : public Sprite
{
public:
~PlayerPlane();
using Sprite::Sprite;
PlayerPlane();
bool emitBullet();
private:
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
PlayerPlane.cpp
#include "PlayerPlane.h"
#include "EntityManager.h"
PlayerPlane::~PlayerPlane()
{
}
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
EntityManager.h
#ifndef ENTITYMANAGER_H_
#define ENTITYMANAGER_H_
#include"Sprite.h"
#include
#include
#include
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())
{
delete e;
return true;
}
return false;
});
}
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
Map.h
#ifndef MAP_H_
#define MAP_H_
#include "Entity.h"
#include
class Map :public Entity
{
public:
Map();
virtual void update() override;
virtual void render(QPainter* painter) override;
private:
QPixmap m_pixmap;
int yPos1,yPos2;
int m_scrollSpeed = 2;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
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;
if (yPos2 >= qGame->height())
{
yPos2 = 0;
}
}
void Map::render(QPainter* painter)
{
painter->drawPixmap(0, yPos1, m_pixmap);
painter->drawPixmap(0, yPos2, m_pixmap);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
Global.h
#ifndef GLOBAL_H_
#define GLOBAL_H_
enum EntityType
{
None,
Player,
Enemy,
bullet
};
#endif
successWidget.h
#ifndef SUCCCESSWIDGET_H_
#define SUCCCESSWIDGET_H_
#include
#include
#include
#include
#include
class successWidget :public QWidget
{
Q_OBJECT
public:
successWidget(QWidget* parent = nullptr);
~successWidget();
protected:
bool eventFilter(QObject* watched, QEvent* event) override;
private:
QPoint m_pos;
};
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
successWidget.cpp
#include "successWidget.h"
#include
#include
#include
#include
#include
#include
successWidget::successWidget(QWidget* parent)
{
{
setFixedSize(300, 300);
setWindowFlag(Qt::FramelessWindowHint, true);
installEventFilter(this);
}
system("cls");
QPushButton* btn1 = new QPushButton("啊,这是什么?");
QPushButton* btn2 = new QPushButton("这很抽象");
QPushButton* btn3 = new QPushButton("尊嘟假嘟");
QPushButton* login = new QPushButton("登录");
btn1->setFixedWidth(100);
btn2->setFixedWidth(100);
btn3->setFixedWidth(100);
QComboBox* love = new QComboBox;
love->addItem("460");
love->addItem("720");
love->addItem("1080");
love->addItem("2k");
love->addItem("4k");
love->addItem("8k");
QLabel* xiaogua = new QLabel;
QLabel* cake = new QLabel;
QLabel* l1 = new QLabel;
QLabel* l2 = new QLabel;
QLabel* l3 = new QLabel;
QLabel* l4 = new QLabel;
QLabel* l5 = new QLabel;
QLabel* l6 = new QLabel;
QLabel* happly = new QLabel("生日快乐呀!");
happly->setFont(QFont("宋体", 18));
xiaogua->setFixedSize(90, 90);
xiaogua->setPixmap(QPixmap(":/plane/Resource/images/xiaogua.bmp"));
xiaogua->setScaledContents(true);
cake->setFixedSize(90, 90);
cake->setPixmap(QPixmap(":/plane/Resource/images/cake2.png"));
cake->setScaledContents(true);
l1->setFixedSize(90, 90);
l1->setPixmap(QPixmap(":/plane/Resource/images/460.png"));
l1->setScaledContents(true);
l2->setFixedSize(90, 90);
l2->setPixmap(QPixmap(":/plane/Resource/images/720.png"));
l2->setScaledContents(true);
l3->setFixedSize(90, 90);
l3->setPixmap(QPixmap(":/plane/Resource/images/1080p.png"));
l3->setScaledContents(true);
l4->setFixedSize(90, 90);
l4->setPixmap(QPixmap(":/plane/Resource/images/2k.png"));
l4->setScaledContents(true);
l5->setFixedSize(90, 90);
l5->setPixmap(QPixmap(":/plane/Resource/images/4k.png"));
l5->setScaledContents(true);
l6->setFixedSize(90, 90);
l6->setPixmap(QPixmap());
l6->setScaledContents(true);
QBoxLayout* hlayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight);
hlayout->addWidget(xiaogua);
hlayout->addWidget(btn1);
this->setLayout(hlayout);
auto passwordLab = new QLabel("密 码");
auto passwordEdit = new QLineEdit;
connect(btn1, &QPushButton::clicked, this, [=]()
{
hlayout->addWidget(btn2);
btn1->close();
qDebug() << "我:啊,这是什么?";
qDebug() << "小瓜:我是小瓜,我是无敌的神,在很久很久很久以前,我········································此处省略......字";
});
connect(btn2, &QPushButton::clicked, this, [=]()
{
hlayout->addWidget(btn3);
qDebug() << "我:这很抽象";
qDebug() << "小瓜:先别管这么多了,你想知道心是什么形状吗?问我这个万能的神就能帮你哦,嘿嘿嘿!";
btn2->close();
});
connect(btn3, &QPushButton::clicked, this, [=]()
{
hlayout->addWidget(love);
btn3->close();
xiaogua->close();
hlayout->addWidget(l1);
qDebug() << "我:尊嘟假嘟";
qDebug() << "小瓜:那当然啦";
}
);
connect(love, &QComboBox::currentTextChanged, this, [=](const QString& text)
{
if (text == "460")
{
hlayout->addWidget(l1);
l2->hide();
l3->hide();
l4->hide();
l5->hide();
l1->show();
}
else if (text == "720")
{
hlayout->addWidget(l2);
l1->hide();
l3->hide();
l4->hide();
l5->hide();
l2->show();
}
else if (text == "1080")
{
hlayout->addWidget(l3);
l2->hide();
l1->hide();
l4->hide();
l5->hide();
l3->show();
}
else if (text == "2k")
{
hlayout->addWidget(l4);
l2->hide();
l3->hide();
l1->hide();
l5->hide();
l4->show();
}
else if (text == "4k")
{
hlayout->addWidget(l5);
l2->hide();
l3->hide();
l4->hide();
l1->hide();
l5->show();
qDebug() << "我:这个就很抽象了";
qDebug() << "小瓜:这多真实,看看8k";
}
else if (text == "8k")
{
l2->hide();
l3->hide();
l4->hide();
l1->hide();
l5->hide();
qDebug() << "小瓜:请输入密码查看8k";
qDebug() << "我:啊,密码是啥?";
qDebug() << "小瓜:啦啦啦,你猜?";
hlayout->addWidget(passwordLab);
passwordEdit->setPlaceholderText("输入密码");
hlayout->addWidget(passwordEdit);
passwordEdit->setEchoMode(QLineEdit::EchoMode::Password);
hlayout->addWidget(login);
}
});
connect(login, &QPushButton::clicked, this, [=]()
{
if (passwordEdit->text() == "1021")
{
love->hide();
passwordLab->hide();
passwordEdit->hide();
login->hide();
hlayout->addWidget(cake);
hlayout->addWidget(happly);
qDebug() << "小瓜:即使在忙碌的日子里,也要祝自己生日快乐呀!";
}
else
{
qDebug() << "小瓜:密码不对哦";
}
}
);
}
successWidget::~successWidget()
{
qDebug() << "successWidget窗口结束";
}
bool successWidget::eventFilter(QObject* watched, QEvent* event)
{
QWidget* w = dynamic_cast<QWidget*>(watched);
if (w->windowFlags() & Qt::FramelessWindowHint)
{
QMouseEvent* ev = dynamic_cast<QMouseEvent*>(event);
if (event->type() == QEvent::MouseButtonPress && ev->button() == Qt::MouseButton::LeftButton)
{
m_pos = ev->pos();
}
else if (event->type() == QEvent::MouseButtonRelease && ev->button() == Qt::MouseButton::LeftButton)
{
m_pos = { 0,0 };
}
else if (event->type() == QEvent::MouseMove && ev->buttons() & Qt::LeftButton)
{
w->move(ev->globalPos() - m_pos);
}
}
return false;
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 运行结果
