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\$
  • \$\begingroup\$ Is delta time in seconds or milli seconds? \$\endgroup\$ – Martin York Aug 1 '12 at 3:08
  • 1
    \$\begingroup\$ @LokiAstari microseconds (SFML supports it) \$\endgroup\$ – rcplusplus Aug 1 '12 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 '12 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\$ – Martin York Aug 1 '12 at 6:04
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, privacy policy and cookie policy

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