0

私はQtを学ぼうとしていますが、少しタイターズゲームを作って学ぼうとしています。現在、ゲームボードを表す2D配列があります。

この2D配列は、毎秒スレッド(時間の経過を表す)によって変更され、このスレッドは、新しいゲームボードに基づいて更新するようにメインGUIに指示する信号を送信します。

私のスレッドは次のとおりです。

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]'の引数をキューに入れることができません('int [20] [10]'がqRegisterMetaType()を使用して登録されていることを確認してください)。

qRegisterMetaTypeとQ_DECLARE_METATYPEを調べましたが、それらの使用方法や、使用する必要があるかどうかさえ、リモートでわかりません。誰かがQT初心者に援助を与えることができますか?

4

2 に答える 2

2

ボードデータをクラスにラップできます。Qtは非配列演算子newを使用してボードデータのインスタンスを作成しようとするため、単にtypedefを実行しただけでは機能しません。コンパイラはそれを検出し、当然のことながら文句を言います。

あなたがしているようにQThreadから派生し、それを一般的なQObjectとして使用するのは悪いスタイルです。QThreadは概念的にはスレッドコントローラであり、スレッド自体ではありません。それを行う慣用的な方法については、この回答を参照してください。GameThreadは、QThreadではなくQObjectである必要があります。

それで:

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();
}
于 2012-06-15T02:16:25.460 に答える
0

後でボードのサイズを変更することにした場合はどうなりますか?ボードの概念をオブジェクトにカプセル化し、そのオブジェクトへのポインタを渡す方がよいと思います。

于 2012-06-14T19:06:17.330 に答える