Reputation: 31
I'm working currently on simple project in Qt. It is based on popular game "Ludo". But I've got annoying problem with making any changes on screen. Board drawing works nice, but it's enough to uncomment line with play() function and disaster guaranteed. Simply I'm not able to setPixmap of field in Player::turn() to show pawns' movement. Scene becomes plain and every drawn field disappears. On the other hand, game runs logically and correctly due to output. Unfortunately, it completely doesn't cooperate with GUI.
I attached images "before-after" and necessary code.
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();
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;
}
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--;
}
}
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;
class Board : public QGraphicsScene {
Q_OBJECT
public:
Board();
virtual ~Board();
void draw();
void drawField(std::vector<Field *> &vec, Vector ¤t, 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;
};
Scene before updating Pixmap
Scene after
What am I doing wrong? How to update my scene in runtime without crash?
Upvotes: 2
Views: 75
Reputation: 12879
Rather than use an infinite loop you could make use of a QTimer
(I see Board
already has a QTimer *
member so perhaps that was the intention all along). Rather than use an explicit timer you might want to use QTimer::singleShot
to `nudge' the game one step forward at a time.
Firstly, make the player counter/index i
a member of Board
and initialise it and dice
in the constructor...
Board::Board ()
: dice(new Dice)
, i(0)
{
...
}
Now change Board::play
so that it makes a single call to Player::turn
for the current player and rearms a timer if required...
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();
});
}
}
I haven't tested the above but it at least shows the basic outline of what you should aim for.
Upvotes: 1