4
\$\begingroup\$

I am having an issue with XNA, where I want to execute some code in my Update method, but only at a given interval, and only once. I would like to avoid booleans to check if I've already called it once, if possible.

My code is here:

    if ((gameTime.TotalGameTime.TotalMilliseconds % 500) == 0)
    {
        Caret.Visible = !Caret.Visible;
    }

As you may have guessed, it's for a TextBox control, to animate the caret between invisible and visible states. I just have reason to believe that it is called twice or maybe even 3 times in a single update-call, which is bad, and makes it look unstable and jumpy.

\$\endgroup\$

2 Answers 2

11
\$\begingroup\$

TotalMilliseconds is a double, so you should not be doing an equality comparison there. There is every chance that the timer gets a fraction of a millisecond off, and your conditional never triggers. Also, there is no mechanism in your description for that code to run more than once per update.

I recommend storing an integer frame number somewhere: int frameNumber;

Then, in your update function, simply do this:

frameNumber++;
Caret.Visible = (((frameNumber / 30) % 2) == 0);

30 frames, at 60 frames per second, is 500 milliseconds.


The alternative method, which is more generally useful, is to store a countdown timer: double timeLeft;

And then do something like this:

timeLeft += gameTime.ElapsedGameTime.TotalMilliseconds;
const double triggerTime = 500;
if(timeLeft > triggerTime)
{
    timeLeft -= triggerTime;
    Caret.Visible = !Caret.Visible;
}

Just to comment on your code, and on mpnk121's answer: It's fine in this case, but in general the downside of using TotalGameTime (instead of ElapsedGameTime) is that you have no mechanism for pausing it.

By the way: 500 milliseconds seems like a very fast rate for a caret blink? Perhaps slow it down a bit.

\$\endgroup\$
3
\$\begingroup\$

Your update function probably isn't called in multiples of 500ms every time, which is what your modulus would imply.

You could save the last time it was called, then compare it with the current time , like

int lastcaret = gameTime.TotalGameTime.TotalMilliseconds;
// in loop
if((gameTime.TotalGameTime.TotalMilliseconds - lastcaret) >= 500)
  ToggleCaret();
  Lastcaret = gameTime.TotalGameTime.TotalMilliseconds;
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .