防止定时器多次更新计数器变量
Preventing the timer from updating the counter variable for more than once
我有一个带有 cpp 的 qt 应用程序。应用程序是落球游戏,当球被篮筐接住时需要增加分数。
该应用程序使用一些 timerEvent 来更新分数。每 10 毫秒调用一次超时槽。我的问题是分数更新了不止一次并且
它的增量是非常随机的。我该如何解决这个问题。
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() <<"mainWindow constructor";
basket = new Basket(this);
sprite = new Sprite(this);
timer=new QTimer(this);
connect(timer, &QTimer::timeout, this, &MainWindow::onTimer);
timer->start(3000);
scoreTimer=new QTimer(this);
connect(scoreTimer, &QTimer::timeout, this, &MainWindow::onScoreTimer);
scoreTimer->start(10);
timerIdForScoreTimer=scoreTimer->timerId();
score = 0;
}
MainWindow::~MainWindow()
{
qDebug() <<"mainWindow destructor";
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(), QBrush(QColor(Qt::white)));
painter.setPen(Qt::black);
painter.setBrush(QBrush(QColor(Qt::darkBlue)));
emit draw(painter);
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Right)
{
emit move(1);
}
if(event->key() == Qt::Key_Left)
{
emit move(0);
}
}
void MainWindow::on_actionStart_triggered()
{
connect(this, &MainWindow::draw, sprite, &Sprite::drawBall);
connect(this, &MainWindow::draw, basket, &Basket::drawBar);
connect(this, &MainWindow::move, basket, &Basket::move);
}
void MainWindow::onTimer()
{
std::cout << "Tick!-----------------------------------------------------------------------------" << std::endl;
sprite = new Sprite(this);
connect(this, &MainWindow::draw, sprite, &Sprite::drawBall);
}
void MainWindow::onScoreTimer()
{
// qDebug() <<"Timer event called in Mainwindow.cpp";
if( (((sprite->y - 15) >= 500)&& sprite->y <530 ) && ( (sprite->x <= (basket->x1 + 80)) && (sprite->x >= (basket->x1 - 80)) ) )
{
// qDebug("x and y position when condition is met and also x1 and y1");
// qDebug()<<x;
// qDebug()<<y;
// qDebug()<<x1;
// qDebug()<<y1;
sprite->dy *= -1;
sprite->dx *= -1;
qDebug() << "score update";
qDebug() <<score;
score ++;
// ui->lcdNumber->setDigitCount(score);
ui->score_label->setText(QVariant(score).toString());
}
}
在 MainWindow::onScoreTimer() 中,“分数”变量随机递增且不止一次。我怎样才能避免这种情况。
因此,在删除所有调试问题后,onScoreTimer()
看起来像这样:
void MainWindow::onScoreTimer()
{
if( (((sprite->y - 15) >= 500)&& sprite->y <530 ) && ( (sprite->x <= (basket->x1 + 80)) && (sprite->x >= (basket->x1 - 80)) ) )
{
sprite->dy *= -1;
sprite->dx *= -1;
score++;
ui->score_label->setText(QVariant(score).toString());
}
}
它反转精灵的方向,增加分数,并更新 score_label
。一切都很好,但请注意,它 不 做的是任何会阻止相同的 if
-测试(在方法的顶部)再次成功的事情下次调用 onScoreTimer()
时。
因此,很有可能当精灵到达目标区域时,onScoreTimer()
(每10毫秒调用一次)会连续多次执行上述所有操作,每次都改变精灵的方向,随着精灵振动 back-and-forth.
至于如何避免这种行为,我可以想到两种可能的解决方案:
- 除了您在上面的代码块中所做的,还将
sprite->x
和 sprite->y
更改为 target-area 之外的某个位置,以便下一次调用onScoreTimer
不会再触发相同的例程。
或
- 添加一个布尔值 member-variable 来跟踪精灵的当前 in-target/not-in-target 状态,并且仅当该变量的状态从 false 变为 true
时才 运行 例程
例如:
class MainWindow {
[...]
private:
bool spriteWasInTarget = false;
};
void MainWindow::onScoreTimer()
{
const bool spriteIsInTarget = ( (((sprite->y - 15) >= 500)&& sprite->y <530 ) && ( (sprite->x <= (basket->x1 + 80)) && (sprite->x >= (basket->x1 - 80)) ) );
if ((spriteIsInTarget)&&(!spriteWasInTarget))
{
sprite->dy *= -1;
sprite->dx *= -1;
score++;
ui->score_label->setText(QVariant(score).toString());
}
spriteWasInTarget = spriteIsInTarget;
}
... 这样例程仅在精灵(重新)进入 target-area.
后的第一次调用时执行
我有一个带有 cpp 的 qt 应用程序。应用程序是落球游戏,当球被篮筐接住时需要增加分数。 该应用程序使用一些 timerEvent 来更新分数。每 10 毫秒调用一次超时槽。我的问题是分数更新了不止一次并且 它的增量是非常随机的。我该如何解决这个问题。
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() <<"mainWindow constructor";
basket = new Basket(this);
sprite = new Sprite(this);
timer=new QTimer(this);
connect(timer, &QTimer::timeout, this, &MainWindow::onTimer);
timer->start(3000);
scoreTimer=new QTimer(this);
connect(scoreTimer, &QTimer::timeout, this, &MainWindow::onScoreTimer);
scoreTimer->start(10);
timerIdForScoreTimer=scoreTimer->timerId();
score = 0;
}
MainWindow::~MainWindow()
{
qDebug() <<"mainWindow destructor";
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(), QBrush(QColor(Qt::white)));
painter.setPen(Qt::black);
painter.setBrush(QBrush(QColor(Qt::darkBlue)));
emit draw(painter);
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Right)
{
emit move(1);
}
if(event->key() == Qt::Key_Left)
{
emit move(0);
}
}
void MainWindow::on_actionStart_triggered()
{
connect(this, &MainWindow::draw, sprite, &Sprite::drawBall);
connect(this, &MainWindow::draw, basket, &Basket::drawBar);
connect(this, &MainWindow::move, basket, &Basket::move);
}
void MainWindow::onTimer()
{
std::cout << "Tick!-----------------------------------------------------------------------------" << std::endl;
sprite = new Sprite(this);
connect(this, &MainWindow::draw, sprite, &Sprite::drawBall);
}
void MainWindow::onScoreTimer()
{
// qDebug() <<"Timer event called in Mainwindow.cpp";
if( (((sprite->y - 15) >= 500)&& sprite->y <530 ) && ( (sprite->x <= (basket->x1 + 80)) && (sprite->x >= (basket->x1 - 80)) ) )
{
// qDebug("x and y position when condition is met and also x1 and y1");
// qDebug()<<x;
// qDebug()<<y;
// qDebug()<<x1;
// qDebug()<<y1;
sprite->dy *= -1;
sprite->dx *= -1;
qDebug() << "score update";
qDebug() <<score;
score ++;
// ui->lcdNumber->setDigitCount(score);
ui->score_label->setText(QVariant(score).toString());
}
}
在 MainWindow::onScoreTimer() 中,“分数”变量随机递增且不止一次。我怎样才能避免这种情况。
因此,在删除所有调试问题后,onScoreTimer()
看起来像这样:
void MainWindow::onScoreTimer()
{
if( (((sprite->y - 15) >= 500)&& sprite->y <530 ) && ( (sprite->x <= (basket->x1 + 80)) && (sprite->x >= (basket->x1 - 80)) ) )
{
sprite->dy *= -1;
sprite->dx *= -1;
score++;
ui->score_label->setText(QVariant(score).toString());
}
}
它反转精灵的方向,增加分数,并更新 score_label
。一切都很好,但请注意,它 不 做的是任何会阻止相同的 if
-测试(在方法的顶部)再次成功的事情下次调用 onScoreTimer()
时。
因此,很有可能当精灵到达目标区域时,onScoreTimer()
(每10毫秒调用一次)会连续多次执行上述所有操作,每次都改变精灵的方向,随着精灵振动 back-and-forth.
至于如何避免这种行为,我可以想到两种可能的解决方案:
- 除了您在上面的代码块中所做的,还将
sprite->x
和sprite->y
更改为 target-area 之外的某个位置,以便下一次调用onScoreTimer
不会再触发相同的例程。
或
- 添加一个布尔值 member-variable 来跟踪精灵的当前 in-target/not-in-target 状态,并且仅当该变量的状态从 false 变为 true 时才 运行 例程
例如:
class MainWindow {
[...]
private:
bool spriteWasInTarget = false;
};
void MainWindow::onScoreTimer()
{
const bool spriteIsInTarget = ( (((sprite->y - 15) >= 500)&& sprite->y <530 ) && ( (sprite->x <= (basket->x1 + 80)) && (sprite->x >= (basket->x1 - 80)) ) );
if ((spriteIsInTarget)&&(!spriteWasInTarget))
{
sprite->dy *= -1;
sprite->dx *= -1;
score++;
ui->score_label->setText(QVariant(score).toString());
}
spriteWasInTarget = spriteIsInTarget;
}
... 这样例程仅在精灵(重新)进入 target-area.
后的第一次调用时执行