Exemplo n.º 1
0
void ParticleEmitter::update(float elapsedTime)
{
    if (!isActive())
    {
        return;
    }

    // Calculate the time passed since last update.
    float elapsedSecs = elapsedTime * 0.001f;

    if (_started && _emissionRate)
    {
        // Calculate how much time has passed since we last emitted particles.
        _timeRunning += elapsedTime;

        // How many particles should we emit this frame?
        GP_ASSERT(_timePerEmission);
        unsigned int emitCount = (unsigned int)(_timeRunning / _timePerEmission);

        if (emitCount)
        {
            if ((int)_timePerEmission > 0)
            {
                _timeRunning = fmod(_timeRunning, (double)_timePerEmission);
            }
            emitOnce(emitCount);
        }
    }

    GP_ASSERT(_node && _node->getScene() && _node->getScene()->getActiveCamera());
    const Frustum& frustum = _node->getScene()->getActiveCamera()->getFrustum();

    // Now update all currently living particles.
    GP_ASSERT(_particles);
    for (unsigned int particlesIndex = 0; particlesIndex < _particleCount; ++particlesIndex)
    {
        Particle* p = &_particles[particlesIndex];
        p->_energy -= elapsedTime;

        if (p->_energy > 0L)
        {
            if (p->_rotationSpeed != 0.0f && !p->_rotationAxis.isZero())
            {
                Matrix::createRotation(p->_rotationAxis, p->_rotationSpeed * elapsedSecs, &_rotation);

                _rotation.transformPoint(p->_velocity, &p->_velocity);
                _rotation.transformPoint(p->_acceleration, &p->_acceleration);
            }

            // Particle is still alive.
            p->_velocity.x += p->_acceleration.x * elapsedSecs;
            p->_velocity.y += p->_acceleration.y * elapsedSecs;
            p->_velocity.z += p->_acceleration.z * elapsedSecs;

            p->_position.x += p->_velocity.x * elapsedSecs;
            p->_position.y += p->_velocity.y * elapsedSecs;
            p->_position.z += p->_velocity.z * elapsedSecs;

            if (!frustum.intersects(p->_position))
            {
                p->_visible = false;
                continue;
            }

            p->_angle += p->_rotationPerParticleSpeed * elapsedSecs;

            // Simple linear interpolation of color and size.
            float percent = 1.0f - ((float)p->_energy / (float)p->_energyStart);

            p->_color.x = p->_colorStart.x + (p->_colorEnd.x - p->_colorStart.x) * percent;
            p->_color.y = p->_colorStart.y + (p->_colorEnd.y - p->_colorStart.y) * percent;
            p->_color.z = p->_colorStart.z + (p->_colorEnd.z - p->_colorStart.z) * percent;
            p->_color.w = p->_colorStart.w + (p->_colorEnd.w - p->_colorStart.w) * percent;

            p->_size = p->_sizeStart + (p->_sizeEnd - p->_sizeStart) * percent;

            // Handle sprite animations.
            if (_spriteAnimated)
            {
                if (!_spriteLooped)
                {
                    // The last frame should finish exactly when the particle dies.
                    float percentSpent = 0.0f;
                    for (unsigned int i = 0; i < p->_frame; i++)
                    {
                        percentSpent += _spritePercentPerFrame;
                    }
                    p->_timeOnCurrentFrame = percent - percentSpent;
                    if (p->_frame < _spriteFrameCount - 1 &&
                        p->_timeOnCurrentFrame >= _spritePercentPerFrame)
                    {
                        ++p->_frame;
                    }
                }
                else
                {
                    // _spriteFrameDurationSecs is an absolute time measured in seconds,
                    // and the animation repeats indefinitely.
                    p->_timeOnCurrentFrame += elapsedSecs;
                    if (p->_timeOnCurrentFrame >= _spriteFrameDurationSecs)
                    {
                        p->_timeOnCurrentFrame -= _spriteFrameDurationSecs;
                        ++p->_frame;
                        if (p->_frame == _spriteFrameCount)
                        {
                            p->_frame = 0;
                        }
                    }
                }
            }
        }
        else
        {
            // Particle is dead.  Move the particle furthest from the start of the array
            // down to take its place, and re-use the slot at the end of the list of living particles.
            if (particlesIndex != _particleCount - 1)
            {
                _particles[particlesIndex] = _particles[_particleCount - 1];
            }
            --_particleCount;
        }
    }
}
Exemplo n.º 2
0
void ParticleEmitter::update(float elapsedTime)
{
    if (!isActive())
        return;

    // Cap particle updates at a maximum rate. This saves processing
    // and also improves precision since updating with very small
    // time increments is more lossy.
    static double runningTime = 0;
    runningTime += elapsedTime;
    if (runningTime < PARTICLE_UPDATE_RATE_MAX)
        return;    

    float elapsedMs = runningTime;
    runningTime = 0;

    float elapsedSecs = elapsedMs * 0.001f;

    if (_started && _emissionRate)
    {
        // Calculate how much time has passed since we last emitted particles.
        _emitTime += elapsedMs; //+= elapsedTime;

        // How many particles should we emit this frame?
        GP_ASSERT(_timePerEmission);
        unsigned int emitCount = (unsigned int)(_emitTime / _timePerEmission);

        if (emitCount)
        {
            if ((int)_timePerEmission > 0)
            {
                _emitTime = fmod((double)_emitTime, (double)_timePerEmission);
            }
            emitOnce(emitCount);
        }
    }

    // Now update all currently living particles.
    GP_ASSERT(_particles);
    for (unsigned int particlesIndex = 0; particlesIndex < _particleCount; ++particlesIndex)
    {
        Particle* p = &_particles[particlesIndex];
        p->_energy -= elapsedMs;

        if (p->_energy > 0L)
        {
            if (p->_rotationSpeed != 0.0f && !p->_rotationAxis.isZero())
            {
                Matrix::createRotation(p->_rotationAxis, p->_rotationSpeed * elapsedSecs, &_rotation);

                _rotation.transformPoint(p->_velocity, &p->_velocity);
                _rotation.transformPoint(p->_acceleration, &p->_acceleration);
            }

            // Particle is still alive.
            p->_velocity.x += p->_acceleration.x * elapsedSecs;
            p->_velocity.y += p->_acceleration.y * elapsedSecs;
            p->_velocity.z += p->_acceleration.z * elapsedSecs;

            p->_position.x += p->_velocity.x * elapsedSecs;
            p->_position.y += p->_velocity.y * elapsedSecs;
            p->_position.z += p->_velocity.z * elapsedSecs;

            p->_angle += p->_rotationPerParticleSpeed * elapsedSecs;

            // Simple linear interpolation of color and size.
            float percent = 1.0f - ((float)p->_energy / (float)p->_energyStart);

            p->_color.x = p->_colorStart.x + (p->_colorEnd.x - p->_colorStart.x) * percent;
            p->_color.y = p->_colorStart.y + (p->_colorEnd.y - p->_colorStart.y) * percent;
            p->_color.z = p->_colorStart.z + (p->_colorEnd.z - p->_colorStart.z) * percent;
            p->_color.w = p->_colorStart.w + (p->_colorEnd.w - p->_colorStart.w) * percent;

            p->_size = p->_sizeStart + (p->_sizeEnd - p->_sizeStart) * percent;

            // Handle sprite animations.
            if (_spriteAnimated)
            {
                if (!_spriteLooped)
                {
                    // The last frame should finish exactly when the particle dies.
                    float percentSpent = 0.0f;
                    for (unsigned int i = 0; i < p->_frame; i++)
                    {
                        percentSpent += _spritePercentPerFrame;
                    }
                    p->_timeOnCurrentFrame = percent - percentSpent;
                    if (p->_frame < _spriteFrameCount - 1 &&
                        p->_timeOnCurrentFrame >= _spritePercentPerFrame)
                    {
                        ++p->_frame;
                    }
                }
                else
                {
                    // _spriteFrameDurationSecs is an absolute time measured in seconds,
                    // and the animation repeats indefinitely.
                    p->_timeOnCurrentFrame += elapsedSecs;
                    if (p->_timeOnCurrentFrame >= _spriteFrameDurationSecs)
                    {
                        p->_timeOnCurrentFrame -= _spriteFrameDurationSecs;
                        ++p->_frame;
                        if (p->_frame == _spriteFrameCount)
                        {
                            p->_frame = 0;
                        }
                    }
                }
            }
        }
        else
        {
            // Particle is dead.  Move the particle furthest from the start of the array
            // down to take its place, and re-use the slot at the end of the list of living particles.
            if (particlesIndex != _particleCount - 1)
            {
                _particles[particlesIndex] = _particles[_particleCount - 1];
            }
            --_particleCount;
        }
    }
}