147 lines
4.7 KiB
C++
147 lines
4.7 KiB
C++
#include "SparkEmitter.h"
|
|
#include <random>
|
|
#include <cmath>
|
|
#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<Vector3f>& 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<Vector3f>& 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<std::chrono::milliseconds>(
|
|
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<SparkParticle>& 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
|