防止定时器多次更新计数器变量

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.

至于如何避免这种行为,我可以想到两种可能的解决方案:

  1. 除了您在上面的代码块中所做的,还将 sprite->xsprite->y 更改为 target-area 之外的某个位置,以便下一次调用onScoreTimer 不会再触发相同的例程。

  1. 添加一个布尔值 member-variable 来跟踪精灵的当前 in-target/not-in-target 状态,并且仅当该变量的状态从 false 变为 true
  2. 时才 运行 例程

例如:

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.

后的第一次调用时执行