Question

I'm making a general timer that has functionality to count up from 0 or count down from a certain number. I also want it to allow the user to add and subtract time. Everything is simple to implement except for the case in which the timer is counting down from some number, and the user adds or subtracts time from it.

For example: (m_clock is an instance of SFML's Clock)

float Timer::GetElapsedTime() {
  if ( m_forward ) {
    m_elapsedTime += m_clock.GetElapsedTime() - m_elapsedTime;
  } else {
    m_elapsedTime -= 
      m_elapsedTime - m_startingTime + m_clock.GetElapsedTime();
  }
  return m_elapsedTime;
}

To be a bit more clear, imagine that the timer starts at 100 counting down. After 10 seconds, the above function would look like 100 -= 100 - 100 + 10 which equals 90. If it was called after 20 more seconds it would look like 90 -= 90 - 100 + 30 which equals 70.

This works for normal counting, but if the user calls AddTime() ( just m_elapsedTime += arg ) then the algorithm for backwards counting fails miserably.

I know that I can do this using more members and keeping track of previous times, etc. but I'm wondering whether I'm missing some implementation that is extremely obvious. I'd prefer to keep it as simple as possible in that single operation.

Was it helpful?

Solution

Your code is unnecessarily complex. The following is equivalent:

float Timer::GetElapsedTime() {
  if ( m_forward ) {
    m_elapsedTime = m_clock.GetElapsedTime();
  } else {
    m_elapsedTime = m_startingTime - m_clock.GetElapsedTime();
  }
  return m_elapsedTime;
}

and hopefully illustrates why AddTime() doesn't work: m_elapsedTime is being replaced on every call to GetElapsedTime(). The simplest solution is track added/subtracted time separately and rework GetElapsedTime() thus:

float Timer::GetElapsedTime() {
  float elapsedTime = m_forward
                      ? m_clock.GetElapsedTime()
                      : m_startingTime - m_clock.GetElapsedTime();
  return elapsedTime + m_addedTime;
}

OTHER TIPS

If you want to increase the time remaining, you can simulate that by decreasing the amount of time elapsed.

Your arithmetic expressions are more complex than they need to be: m_elapsedTime += m_clock.GetElapsedTime() - m_elapsedTime is equivalent to m_elapsedTime = m_clock.GetElapsedTime(), and m_elapsedTime -= m_elapsedTime - m_startingTime + m_clock.GetElapsedTime() is equivalent to m_elapsedTime = m_startingTime - m_clock.GetElapsedTime()`.

At this point, the problem is clear: the old value of m_elapsedTime never affects the subsequent result. I would consider adding in an offset field to handle any changes to the starting value of the timer. At this point, Timer:GetElapsedTime could just be the following:

float Timer::GetElapsedTime() {
  if ( m_forward ) {
    return offset + m_clock.GetElapsedTime();
  } else {
    return offset - m_clock.GetElapsedTime();
  }
}

where offset starts at 0 for a count-up and the start value for a count-down. Make sure and watch your signs for updating offset in AddTime()

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top