当健康为0时如何在Qt中退出“游戏”
Posted
技术标签:
【中文标题】当健康为0时如何在Qt中退出“游戏”【英文标题】:How to exit a "game" in Qt when health is 0 【发布时间】:2016-02-08 18:37:13 【问题描述】:我对 Qt 很陌生,但我开始尝试制作 2D 游戏。我有一个非常粗糙和简单的游戏开始,但我有一个问题。每当生命值变为 0 时,游戏就不会结束。我只想知道如何结束游戏以及在制作“游戏结束”屏幕之前将此退出命令放在哪里。我的代码在下面,据我所知,我假设 QApplication::quit() 位于 Game.cpp 文件中。通过从 Health.cpp 和 Health.h 中获取健康整数并将其放入 Game.cpp 中来做到这一点。任何帮助表示赞赏。这是我觉得答案所在的代码,如果需要更多信息,请询问。
Game.h
#ifndef GAME_H
#define GAME_H
#include <QGraphicsView>
#include <QWidget>
#include <QGraphicsScene>
#include "Player.h"
#include "Score.h"
#include "Health.h"
#include "Level.h"
#include "Main.h"
class Game: public QGraphicsView
public:
Game(QWidget * parent=0);
QGraphicsScene * scene;
Player * player;
Score * score;
Health * health;
Level * level;
Main * close;
int end();
;
#endif // GAME_H
Game.cpp
#include "Game.h"
#include <QTimer>
#include <QGraphicsTextItem>
#include <QFont>
#include "Enemy.h"
#include <QMediaPlayer>
#include <QBrush>
#include <QImage>
#include <QApplication>
Game::Game(QWidget *parent)
// create the scene
scene = new QGraphicsScene();
scene->setSceneRect(0,0,800,600); // make the scene 800x600 instead of infinity by infinity (default)
setBackgroundBrush(QBrush(QImage(":/images/bg.png")));
// make the newly created scene the scene to visualize (since Game is a QGraphicsView Widget,
// it can be used to visualize scenes)
setScene(scene);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFixedSize(800,600);
// create the player
player = new Player();
player->setPos(400,500); // TODO generalize to always be in the middle bottom of screen
// make the player focusable and set it to be the current focus
player->setFlag(QGraphicsItem::ItemIsFocusable);
player->setFocus();
// add the player to the scene
scene->addItem(player);
// create the score/health
score = new Score();
scene->addItem(score);
health = new Health();
health->setPos(health->x(),health->y()+25);
scene->addItem(health);
level = new Level();
scene->addItem(level);Bull
level->setPos(level->x(),level->y()+50);
// spawn enemies
QTimer * timer = new QTimer();
QObject::connect(timer,SIGNAL(timeout()),player,SLOT(spawn()));
timer->start(2000);
// play background music
QMediaPlayer * music = new QMediaPlayer();
music->setMedia(QUrl("qrc:/sounds/bgsound.mp3"));
music->play();
show();
int Game::end()
if (health == 0)
QApplication::quit();
return 0;
Health.h
#ifndef HEALTH_H
#define HEALTH_H
#include <QGraphicsTextItem>
class Health: public QGraphicsTextItem
public:
Health(QGraphicsItem * parent=0);
void decrease();
int getHealth();
private:
int health;
;
#endif // HEALTH_H
Health.cpp
#include "Health.h"
#include <QFont>
#include <QApplication>
Health::Health(QGraphicsItem *parent): QGraphicsTextItem(parent)
// initialize the score to 0
health = 3;
// draw the text
setPlainText(QString("Health: ") + QString::number(health)); // Health: 3
setDefaultTextColor(Qt::red);
setFont(QFont("times",16));
void Health::decrease()
health--;
setPlainText(QString("Health: ") + QString::number(health)); // Health: 2
int Health::getHealth()
return health;
main.cpp
#include <QApplication>
#include "Game.h"
#include "Main.h"
Game * game;
int main(int argc, char *argv[])
QApplication a(argc, argv);
game = new Game();
game->show();
return a.exec();
【问题讨论】:
【参考方案1】:您的 end()
函数永远不会被调用。
实现您想要的最佳方式是使用Qt's signal/slot mechanism。将事件(信号)连接到动作(槽)变得很容易:
在Health
和Game
类中添加Q_OBJECT
宏并确保你的编译环境moc's这两个头文件
在Health
中声明一个名为signal
的dead()
从Health::decrease()
发出信号
使Game::end()
成为slot
和void
将Health::dead()
连接到Game::end()
然后,一旦Health
达到零,Game::end()
就会被调用。
class Health: public QGraphicsTextItem
Q_OBJECT
public:
Health(QGraphicsItem * parent=0);
void decrease();
int getHealth();
signals:
void dead();
private:
int health;
;
...
class Game: public QGraphicsView
Q_OBJECT
public:
...
public slots:
void end();
;
...
void Health::decrease()
health--;
setPlainText(QString("Health: ") + QString::number(health));
if ( health == 0 )
emit dead();
...
Game::Game(QWidget *parent)
...
connect( health, SIGNAL(dead()), this, SLOT(end()) );
...
void Game::end()
// no need to test health anymore, as signal is emited when health is zero
// do some extra stuff before exiting
QApplication::quit();
如果end()
只调用QApplication::quit()
,你可以去掉它直接将信号连接到QApplication::quit()
,像这样:
connect( health, SIGNAL(dead()), qApp, SLOT(quit()) );
还请注意,您在Game::end()
中测试health == 0
,但health
是一个指针,而且,查看您的代码,它永远不会是0
(您可能打算写if ( health->getHealth() == 0 )
。
【讨论】:
你说的都做了,但是当我编译我得到错误“未定义的对 Health::dead() 的引用”并指向行if (health==0)
emit dead();
。现在怎么了?
你moc Health.h了吗?
我没有,但是当我将 Q_OBJECT 添加到 Health.h 时,我现在在编译时遇到了更多错误,在函数 Health::decrease 和 Health.cpp 中添加了“未定义的对 vtable 的引用”,同时仍然有“未定义的引用”错误。挫败感在 >.>
如果你正在编写基于 Qt 的代码,你将不得不处理 moc 的东西。您需要对任何带有 Q_OBJECT 宏的头文件进行移动(这是特定于 Qt 的编译步骤,请参阅doc.qt.io/qt-5/moc.html)。 QtCreator 会为你做这件事,如果你不使用 QtCreator,你的 IDE 可能会有一个插件(如果使用 CMake,还有一个 Visual Studio 插件和一些 CMake 宏)。如果你不能让 Q_OBJECT 工作,你不能使用signa/slots,那么你就不能使用Qt...
请阅读:***.com/questions/2555816/….【参考方案2】:
在Health::decrease
中发出一个信号或将其逻辑放在“玩家被击中”区域的位置。 但要做到这一点,你到 编辑Health
或逻辑为QObject
的类,以便它获取标头中的信号和插槽。QGraphicsTextItem
已经是@987654327 @。见 cmets。
在实例化 Health 类或 Player 类后立即将信号连接到视图的 close()
。
http://doc.qt.io/qt-5/signalsandslots.html
希望对您有所帮助。
【讨论】:
Health
已经是QObject
(派生自QGraphicsTextItem
)
你是对的;谢谢你让我诚实。我最近没有查看文档。 doc.qt.io/qt-5/qgraphicsobject.html 但是,大多数库存 QGraphicsItems 不是 QGraphicsObjects
。只有QGraphicsSvgItem, QGraphicsTextItem, QGraphicsVideoItem,' and 'QGraphicsWidget
是QObjects。
这似乎是使用Q_PROPERTY
的好地方。如果您右键单击并在 Qt Creator 中使用 Refactor...
,您可以非常快速地获取所有的 setter 和 getter、信号和插槽以及所有内容。以上是关于当健康为0时如何在Qt中退出“游戏”的主要内容,如果未能解决你的问题,请参考以下文章
如何修复由 cx_Freeze 转换为 exe 的 pygame 中的游戏?
当 Application.Current 为 NULL 时如何退出 wpf 应用程序?