QGraphicsScene вылетает даже после крошечного обновления - PullRequest
0 голосов
/ 13 февраля 2019

Сейчас я работаю над простым проектом в Qt.Он основан на популярной игре "Людо".Но у меня есть раздражающая проблема с внесением каких-либо изменений на экране.Рисование доски работает хорошо, но этого достаточно, чтобы раскомментировать строку с функцией play () и гарантированной аварийной ситуацией.Просто я не могу установить Pixmap поля в Player :: turn (), чтобы показать движение пешек.Сцена становится простой, и каждое нарисованное поле исчезает.С другой стороны, игра работает логично и корректно благодаря выводу.К сожалению, он полностью не взаимодействует с GUI.

Я прикрепил изображения «до-после» и необходимый код.

main.cpp

QApplication a(argc, argv);

Board *scene = new Board();

QGraphicsView *view = new QGraphicsView(scene);
view->resize(1200, 1000);
view->show();

scene->draw();
// scene->play();

return a.exec();

Board :: play ()

dice = new Dice();
unsigned int i=0;
while(true) {

    bool playMore = players.at(i)->turn(dice, players, fieldsToPlay);
    if(playMore) {

        i++;
        if(i == 4)
            i=0;
    }
    else break;
}

Player :: turn ()

int result;
std::cout << "Player " << colour << " ";

if(hasPawnOnField) {

    // TODO: check if field has pawn
    result = dice->roll();
    std::cout << result << '\n';

    while(result) {

        pawns.at(0)->currentField->set_Pixmap(QPixmap(":/img/border.png"));
        pawns.at(0)->currentField->setPawn(nullptr);
        bool finito = pawns.at(0)->move(fieldsToPlay, baseAndFinish);
        pawns.at(0)->currentField->setPawn(pawns.at(0));


        char col = pawns.at(0)->getColour();
        switch (col) {

            case 'b':
                pawns.at(0)->currentField->set_Pixmap(QPixmap(":/img/bluepawn.png"));
                break;
            case 'r':
                pawns.at(0)->currentField->set_Pixmap(QPixmap(":/img/redpawn.png"));
                break;
            case 'y':
                pawns.at(0)->currentField->set_Pixmap(QPixmap(":/img/yellowpawn.png"));
                break;
            case 'g':
                pawns.at(0)->currentField->set_Pixmap(QPixmap(":/img/greenpawn.png"));
                break;
        }

        if(finito) {

            finishedPawns++;
            delete pawns.at(0);
            pawns.erase(pawns.begin());
            hasPawnOnField = false;
            break;
        }

        result--;
    }
    if(finishedPawns == 4) // condition which ends the game
        return 0;
}
else {

   int attempts = 3;

   while(attempts) {

       result = dice->roll();
       std::cout << result << '\n';
       if(result == 6) {

           hasPawnOnField = true;
           if(start->getPawn()) {

              char col = start->getPawn()->getColour();
              switch (col) {

                case 'b':
                  players.at(0)->pawns.at(0)->setField(fieldsToPlay.at(0));
                  players.at(0)->pawns.at(0)->zero();
                  fieldsToPlay.at(0)->setPawn(players.at(0)->pawns.at(0));
                  fieldsToPlay.at(0)->set_Pixmap(QPixmap(":/img/bluepawn.png"));
                  break;
                case 'r':
                  players.at(1)->pawns.at(0)->setField(fieldsToPlay.at(12));
                  players.at(1)->pawns.at(0)->zero();
                  fieldsToPlay.at(12)->setPawn(players.at(1)->pawns.at(0));
                  fieldsToPlay.at(12)->set_Pixmap(QPixmap(":/img/redpawn.png"));
                  break;
                case 'y':
                  players.at(2)->pawns.at(0)->setField(fieldsToPlay.at(24));
                  players.at(2)->pawns.at(0)->zero();
                  fieldsToPlay.at(24)->setPawn(players.at(2)->pawns.at(0));
                  fieldsToPlay.at(24)->set_Pixmap(QPixmap(":/img/yellowpawn.png"));
                  break;
                case 'g':
                  players.at(3)->pawns.at(0)->setField(fieldsToPlay.at(36));
                  players.at(3)->pawns.at(0)->zero();
                  fieldsToPlay.at(36)->setPawn(players.at(3)->pawns.at(0));
                  fieldsToPlay.at(36)->set_Pixmap(QPixmap(":/img/greenpawn.png"));
                  break;
              }
           }
           pawns.at(0)->setField(start);
           start->setPawn(pawns.at(0));
           start->set_Pixmap(baseAndFinish.at(finishedPawns)->getPixmap());

           baseAndFinish.at(finishedPawns)->set_Pixmap(QPixmap(":/img/border.png"));
           break;
       }

       attempts--;
   }
}

Pawn :: move ()

passedFields++;

if(passedFields >= 48) {

    currentField = basFin.at(4+(passedFields-48));

    if(passedFields == FINISH) {
        FINISH--;
        delete basFin.at(basFin.size()-1);
        basFin.pop_back();
        return true;
    }

}
else
    currentField = fieldsToPlay.at( (startID+passedFields)%48);

return false;

Board.h

class Board : public QGraphicsScene {

Q_OBJECT

public:

Board();
virtual ~Board();
void draw();
void drawField(std::vector<Field *> &vec, Vector &current, Vector dir, QString image);
void play();

static const int rect_size = 70;

Vector directions[4] = {Vector (0, -rect_size),   //up
                        Vector (rect_size, 0),    //right
                        Vector (0, rect_size),    //down
                        Vector (-rect_size, 0) }; //left

private:
std::vector<Field *> fieldsToPlay;
std::vector<Player *> players;

std::vector<Field *> fieldsBlue;    //fields 0-3 basement, fields 4-7 finish
std::vector<Field *> fieldsRed;
std::vector<Field *> fieldsYellow;
std::vector<Field *> fieldsGreen;

Dice *dice;
QTimer *timer;
};

Сцена перед обновлением Pixmap

Сцена после

Что я делаю не так?Как обновить мою сцену во время выполнения без сбоев?

1 Ответ

0 голосов
/ 13 февраля 2019

Вместо того, чтобы использовать бесконечный цикл, вы можете использовать QTimer (я вижу, Board уже имеет член QTimer *, так что, возможно, это было намерением с самого начала).Вместо использования явного таймера вы можете использовать QTimer::singleShot, чтобы «подтолкнуть» игру на один шаг вперед за один раз.

Во-первых, сделайте счетчик / индекс игрока iчлен Board и инициализация его и dice в конструкторе ...

Board::Board ()
    : dice(new Dice)
    , i(0)
{
     ...
}

Теперь измените Board::play так, чтобы он сделал один вызов Player::turn для текущего игрока и тыловтаймер, если требуется ...

void Board::play ()
{

    /*
     * Give the current player their turn.
     */
    bool playMore = players.at(i)->turn(dice, players, fieldsToPlay);
    if (playMore) {

        /*
         * The game hasn't yet finished so update the player index
         * and rearm the timer with a lambda to make another call
         * to play() in 1 second.
         */
        i++;
        if (i == 4)
            i=0;
        QTimer::singleShot(1000,
                           [this]()
                           {
                               play();
                           });
    }
}

Я не проверял вышеизложенное, но он, по крайней мере, показывает базовый план того, к чему вы должны стремиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...