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

发布于 2025-01-27 03:16:13 字数 2662 浏览 2 评论 0原文

我有一个带有CPP的QT应用程序。当球被篮球捕获时,应用程序是落球的比赛,得分需要增加。 该应用程序使用一些时间探测来更新分数。每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()“得分”变量被随机增量,不止一次。我该如何防止这种情况。

I have a qt application with cpp. The application is Falling ball game, when the ball is catched by basket the score needs to be incremented.
The application uses some timerEvent to update the score. The slot for timeout is called for every 10 msec. My problem is the score is updated more than once and
is very random in its incrementation. How can I solve this problem.

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());
    }
}

In MainWindow::onScoreTimer() the "score" variable is incremented randomly and more than once. How can I prevent this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

初见你 2025-02-03 03:16:13

因此,删除了所有调试的cruft,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。一切都很好,但是请注意,如果 做的事情是阻止相同 -test(在方法的顶部)再次成功的任何事情下次调用onscoreTimer()

因此,当精灵到达目标区域时,onscoreTimer()(每10ms称为每10ms)完全有可能执行上述所有次数,每次都会更改精灵的方向,随着雪橇振动的振动,增加得分很大。

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

  1. 以及您在上述代码中所做的事情,也更改sprite-&gt; xsprite- &gt; y到目标区域外的某个位置,因此下一个呼叫onscoreTimer不会再次触发相同的例程。

  1. 添加布尔成员 - 可变性以跟踪精灵的当前目标/不靶标状态,并且仅在该变量状态从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;
}

时才 例程Sprite(RE)进入目标区域后的第一个呼叫执行。

So with all the debugging cruft removed, onScoreTimer() looks like this:

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());
   }
}

It reverses the sprite's direction, increments the score, and updates the score_label. All well and good, but note that what it doesn't do is anything that would prevent that same if-test (at the top of the method) from succeeding again the next time onScoreTimer() is called.

Therefore, it's entirely likely that when the sprite reaches the target area, onScoreTimer() (which is called every 10mS) will do all of the above many times in a row, changing the sprite's direction every time, and increasing the score quite a bit as the sprite vibrates back-and-forth.

As for how to avoid that behavior, I can think of two possible solutions:

  1. Along with what you're doing inside the above block of code, also change sprite->x and sprite->y to some location outside of the target-area, so that the next call to onScoreTimer won't trigger the same routine again.

or

  1. Add a boolean member-variable to track the current in-target/not-in-target state of the sprite, and only run the routine when that variable's state changes from false to true

e.g.:

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;
}

... so that way the routine only executes on the first call after the sprite (re)enters the target-area.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文