7
\$\begingroup\$

I'm using the cosine function in C++ to simulate flashing for a sprite in my game. The method looks like this:

(anything in the sf namespace is part of the SFML graphics library)

void Player::update(const float& deltaTime)
{
    mAccumulatedTime += deltaTime;
    float opacity = abs(cosf(5*mAccumulatedTime)) * 255;
    static int numFlashes = 0;
    if (opacity == 255) {
        cout << ++numFlashes << endl;
    }
    mSprite.setFillColor(sf::Color(255, 255, 255, opacity));
}

So every time opacity is equal to 255 (basically the passing of one full period), numFlashes should be incremented. The problem is, cos() isn't perfect, meaning it doesn't exactly reach 1 and 0, so the if condition is rarely met. If I use rough checking like if (opacity > 255*0.9999), then numFlashes becomes really high, really fast.

Does anyone know a way to accurately check when a full period has passed? Or is that just not possible?

\$\endgroup\$
4
  • \$\begingroup\$ Is delta time in seconds or milli seconds? \$\endgroup\$ Aug 1, 2012 at 3:08
  • 1
    \$\begingroup\$ @LokiAstari microseconds (SFML supports it) \$\endgroup\$
    – rcplusplus
    Aug 1, 2012 at 3:18
  • \$\begingroup\$ @LokiAstari it's actually not supposed to be in microseconds... I just fixed that problem by dividing deltaTime by 1,000,000 in the method-call, so NOW it's in seconds. \$\endgroup\$
    – rcplusplus
    Aug 1, 2012 at 3:24
  • \$\begingroup\$ Note: cosf() parameter is in radians. So it will get back to 1 every 2.pi/5 seconds (apprx 1.25 seconds). But since you are using abs() on it 0.625 seconds. \$\endgroup\$ Aug 1, 2012 at 6:04

2 Answers 2

6
\$\begingroup\$

One may use the following closed formula to compute numFlashes:

numFlashes = 5 * mAccumulatedTime / pi.

This follows from the fact that the period of the function abs(cos(x)) is pi and, if an oscillating function in variable x has a period T, then the number of oscillations, n, is given by the formula:

n = x / T.

Thus, your function definition may be corrected, and even simplified, as follows:

const float PI = acosf(-1);

void Player::update(const float& deltaTime)
{
    mAccumulatedTime += deltaTime;
    float opacity = abs(cosf(5*mAccumulatedTime)) * 255;
    int numFlashes = 5 * mAccumulatedTime / PI;
    cout << numFlashes << endl;
    mSprite.setFillColor(sf::Color(255, 255, 255, opacity));
}
\$\endgroup\$
1
\$\begingroup\$

Is it critical that you flash on the maximum? You could change it to flash as it crosses a value if not.

double CalcOpacity( const float& accTime )
{
    return (cosf(PERIOD*mAccumulatedTime)) * AMPLITUDE;
}

void Player::update(const float& deltaTime)
{
    float old_opacity = CalcOpacity( mAccumulatedTime );
    mAccumulatedTime += deltaTime;
    float opacity = CalcOpacity( mAccumulatedTime );
    static int numFlashes = 0;
    if ( ( old_opacity < 0 ) && ( opacity >= 0 ) ) {// and the other direction
        cout << ++numFlashes << endl;
    }
    mSprite.setFillColor(sf::Color(255, 255, 255, abs(opacity)));
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.