我正在努力学习Qt,我试图通过制作一个小滴度游戏来做到这一点。目前我有一个代表游戏板的2D阵列。
这个2d数组每秒都被一个线程改变(代表时间的推移),然后这个线程发出一个信号,告诉主GUI根据新的游戏板进行更新。
My Thread如下:
gamethread.h
#ifndef GAMETHREAD_H
#define GAMETHREAD_H
#include <QtCore>
#include <QThread>
#include<QMetaType>
class GameThread : public QThread
{
Q_OBJECT
public:
explicit GameThread(QObject *parent = 0);
void run();
private:
int board[20][10]; //[width][height]
void reset();
signals:
void TimeStep(int board[20][10]);
};
#endif // GAMETHREAD_H
gamethread.cpp
#include "gamethread.h"
#include <QtCore>
#include <QtDebug>
//Game Managment
GameThread::GameThread(QObject *parent) :
QThread(parent)
{
reset();
}
void GameThread::reset()
{
...
}
//Running The Game
void GameThread::run()
{
//Do Some Stuff
emit TimeStep(board);
}
并且应该接收信号并基于新板更新的主UI是:
tetris.h
#ifndef TETRIS_H
#define TETRIS_H
#include <QMainWindow>
#include "gamethread.h"
namespace Ui{
class Tetris;
}
class Tetris : public QMainWindow
{
Q_OBJECT
public:
explicit Tetris(QWidget *parent = 0);
~Tetris();
GameThread *mainThread;
private:
Ui::Tetris *ui;
private slots:
int on_action_Quit_activated();
void on_action_NewGame_triggered();
public slots:
void onTimeStep(int board[20][10]);
};
#endif // TETRIS_H
tetris.cpp
#include <QMessageBox>
#include <QtGui>
#include <boost/lexical_cast.hpp>
#include <string>
#include "tetris.h"
#include "ui_tetris.h"
Tetris::Tetris(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Tetris)
{
ui->setupUi(this);
mainThread = new GameThread(this);
connect(mainThread, SIGNAL(TimeStep(int[20][10])),
this, SLOT(onTimeStep(int[20][10])),
Qt::QueuedConnection);
}
Tetris::~Tetris()
{
delete ui;
}
void Tetris::onTimeStep(int board[20][10])
{
//receive new board update my display
}
void Tetris::on_action_NewGame_triggered()
{
mainThread->start();
}
当我跑步时,我得到:
QObject :: connect:无法对类型为'int [20] [10]'的参数进行排队 (确保使用qRegisterMetaType()注册'int [20] [10]'。)
我已经研究过qRegisterMetaType和Q_DECLARE_METATYPE,但我甚至不确定如何使用它们,即使我必须使用它们。有人可以给QT新手一些帮助吗?
答案 0 :(得分:2)
您可以将电路板数据包装在一个类中。如果你只是键入它,它将无法工作,因为Qt将尝试使用非数组运算符new来创建板数据的实例。编译器将检测它并正确地抱怨。
从你正在做的QThread派生并使用它作为通用QObject是不好的风格。 QThread在概念上是一个线程控制器,而不是一个线程本身。有关惯用的方法,请参阅this answer。你的GameThread应该是QObject,而不是QThread。
所以:
struct Board {
int data[20][10];
}
Q_DECLARE_METATYPE(Board);
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
qRegisterMetatype<Board>("Board");
...
Game * game = new Game;
QThread thread;
game->connect(&thread, SIGNAL(started()), SLOT(start());
game->connect(game, SIGNAL(finished()), SLOT(deleteLater()));
thread.connect(&game, SIGNAL(finished()), SLOT(quit());
game.moveToThread(&thread);
thread.start(); // you can start the thread later of course
return app.exec();
}
class Game: public QObject
{
QTimer timer;
Board board;
public slots:
void start() {
connect(&timer, SIGNAL(timeout()), SLOT(tick()));
timer.start(1000); // fire every second
}
void finish() {
timer.stop();
emit finished();
}
protected slots:
void tick() {
... // do some computations that may take a while
emit newBoard(board);
// Note: it probably doesn't apply to trivial computations in
// a Tetris game, but if the computations take long and variable
// time, it's better to emit the board at the beginning of tick().
// That way the new board signal is always synchronized to the timer.
}
signals:
void newBoard(const Board &);
void finished();
}
答案 1 :(得分:0)
如果您以后决定更改电路板的尺寸,会发生什么?我认为最好将一个板的概念封装在一个对象中,并传递一个指向所述对象的指针。