#include "SparkEmitter.h" #include #include #include "OpenGlExtensions.h" namespace ZL { SparkEmitter::SparkEmitter() : emissionRate(100.0f), isActive(true) { particles.resize(200); lastEmissionTime = std::chrono::steady_clock::now(); } SparkEmitter::SparkEmitter(const std::vector& positions, float rate) : emissionPoints(positions), emissionRate(rate), isActive(true) { particles.resize(positions.size() * 100); lastEmissionTime = std::chrono::steady_clock::now(); } void SparkEmitter::setEmissionPoints(const std::vector& positions) { emissionPoints = positions; particles.resize(positions.size() * 100); } void SparkEmitter::setEmissionRate(float rateMs) { emissionRate = rateMs; } void SparkEmitter::setActive(bool active) { isActive = active; } void SparkEmitter::update(float deltaTimeMs) { auto currentTime = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast( currentTime - lastEmissionTime).count(); if (isActive && elapsed >= emissionRate) { emit(); lastEmissionTime = currentTime; } for (auto& particle : particles) { if (particle.active) { particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f; particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f; particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f; particle.lifeTime += deltaTimeMs; if (particle.lifeTime >= particle.maxLifeTime) { particle.active = false; } float lifeRatio = particle.lifeTime / particle.maxLifeTime; particle.scale = 1.0f - lifeRatio * 0.8f; } } } void SparkEmitter::emit() { if (emissionPoints.empty()) return; for (int i = 0; i < emissionPoints.size(); ++i) { bool particleFound = false; for (auto& particle : particles) { if (!particle.active) { initParticle(particle, i); particle.active = true; particle.lifeTime = 0; particle.position = emissionPoints[i]; particle.emitterIndex = i; particleFound = true; break; } } if (!particleFound && !particles.empty()) { size_t oldestIndex = 0; float maxLifeTime = 0; for (size_t j = 0; j < particles.size(); ++j) { if (particles[j].lifeTime > maxLifeTime) { maxLifeTime = particles[j].lifeTime; oldestIndex = j; } } initParticle(particles[oldestIndex], i); particles[oldestIndex].active = true; particles[oldestIndex].lifeTime = 0; particles[oldestIndex].position = emissionPoints[i]; particles[oldestIndex].emitterIndex = i; } } } void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) { particle.velocity = getRandomVelocity(emitterIndex); particle.scale = 1.0f; particle.maxLifeTime = 800.0f + (rand() % 400); // От 800 до 1200 мс particle.emitterIndex = emitterIndex; } Vector3f SparkEmitter::getRandomVelocity(int emitterIndex) { static std::random_device rd; static std::mt19937 gen(rd()); static std::uniform_real_distribution<> angleDist(0, 2 * M_PI); static std::uniform_real_distribution<> speedDist(0.5f, 2.0f); static std::uniform_real_distribution<> zSpeedDist(1.0f, 3.0f); float angle = angleDist(gen); float speed = speedDist(gen); float zSpeed = zSpeedDist(gen); if (emitterIndex == 0) { return Vector3f{ cosf(angle) * speed - 0.3f, sinf(angle) * speed, zSpeed }; } else { return Vector3f{ cosf(angle) * speed + 0.3f, sinf(angle) * speed, zSpeed }; } } const std::vector& SparkEmitter::getParticles() const { return particles; } size_t SparkEmitter::getActiveParticleCount() const { size_t count = 0; for (const auto& particle : particles) { if (particle.active) { count++; } } return count; } } // namespace ZL