fix spark

This commit is contained in:
Vlad 2025-12-11 20:09:41 +06:00
parent b855cff0e6
commit 115cbbb7fa
4 changed files with 760 additions and 673 deletions

970
Game.cpp

File diff suppressed because it is too large Load Diff

90
Game.h
View File

@ -9,59 +9,59 @@
namespace ZL { namespace ZL {
struct BoxCoords struct BoxCoords
{ {
Vector3f pos; Vector3f pos;
Matrix3f m; Matrix3f m;
}; };
class Game { class Game {
public: public:
Game(); Game();
~Game(); ~Game();
void setup();
void update();
void render();
bool shouldExit() const { return Environment::exitGameLoop; }
private: void setup();
void processTickCount(); void update();
void drawScene(); void render();
void drawCubemap();
void drawEffects();
void drawShip();
void drawBoxes();
SDL_Window* window; bool shouldExit() const { return Environment::exitGameLoop; }
SDL_GLContext glContext;
Renderer renderer;
size_t newTickCount;
size_t lastTickCount;
static const size_t CONST_TIMER_INTERVAL = 10;
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
std::shared_ptr<Texture> sparkTexture; private:
std::shared_ptr<Texture> spaceshipTexture; void processTickCount();
std::shared_ptr<Texture> cubemapTexture; void drawScene();
VertexDataStruct spaceshipBase; void drawCubemap();
VertexRenderStruct spaceship; void drawEffects();
void drawShip();
void drawBoxes();
VertexRenderStruct cubemap; SDL_Window* window;
SDL_GLContext glContext;
Renderer renderer;
std::shared_ptr<Texture> boxTexture; size_t newTickCount;
VertexDataStruct boxBase; size_t lastTickCount;
std::vector<BoxCoords> boxCoordsArr; static const size_t CONST_TIMER_INTERVAL = 10;
std::vector<VertexRenderStruct> boxRenderArr; static const size_t CONST_MAX_TIME_INTERVAL = 1000;
//VertexRenderStruct singleSpark; std::shared_ptr<Texture> sparkTexture;
SparkEmitter sparkEmitter; std::shared_ptr<Texture> spaceshipTexture;
VertexRenderStruct sparkQuad; std::shared_ptr<Texture> cubemapTexture;
}; VertexDataStruct spaceshipBase;
VertexRenderStruct spaceship;
VertexRenderStruct cubemap;
std::shared_ptr<Texture> boxTexture;
VertexDataStruct boxBase;
std::vector<BoxCoords> boxCoordsArr;
std::vector<VertexRenderStruct> boxRenderArr;
//VertexRenderStruct singleSpark;
SparkEmitter sparkEmitter;
VertexRenderStruct sparkQuad;
};
} // namespace ZL } // namespace ZL

View File

@ -5,143 +5,207 @@
namespace ZL { namespace ZL {
SparkEmitter::SparkEmitter() SparkEmitter::SparkEmitter()
: emissionRate(100.0f), isActive(true) { : emissionRate(100.0f), isActive(true), buffersDirty(true), maxParticles(200) {
particles.resize(200); particles.resize(maxParticles);
lastEmissionTime = std::chrono::steady_clock::now(); positionBuffer.resize(maxParticles * 4, 0.0f);
} texCoordBuffer.resize(maxParticles * 2, 0.0f);
lastEmissionTime = std::chrono::steady_clock::now();
}
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate) SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
: emissionPoints(positions), emissionRate(rate), isActive(true) { : emissionPoints(positions), emissionRate(rate), isActive(true),
particles.resize(positions.size() * 100); buffersDirty(true), maxParticles(positions.size() * 100) {
lastEmissionTime = std::chrono::steady_clock::now(); particles.resize(maxParticles);
} positionBuffer.resize(maxParticles * 4, 0.0f);
texCoordBuffer.resize(maxParticles * 2, 0.0f);
lastEmissionTime = std::chrono::steady_clock::now();
}
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) { void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
emissionPoints = positions; emissionPoints = positions;
particles.resize(positions.size() * 100); maxParticles = positions.size() * 100;
} particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f);
texCoordBuffer.resize(maxParticles * 2, 0.0f);
buffersDirty = true;
}
void SparkEmitter::setEmissionRate(float rateMs) { void SparkEmitter::updateBuffers() {
emissionRate = rateMs; if (!buffersDirty) return;
}
void SparkEmitter::setActive(bool active) { size_t bufferIndex = 0;
isActive = active; for (const auto& particle : particles) {
} if (particle.active) {
positionBuffer[bufferIndex * 4] = particle.position.v[0];
positionBuffer[bufferIndex * 4 + 1] = particle.position.v[1];
positionBuffer[bufferIndex * 4 + 2] = particle.position.v[2];
positionBuffer[bufferIndex * 4 + 3] = particle.scale;
void SparkEmitter::update(float deltaTimeMs) { texCoordBuffer[bufferIndex * 2] = 0.0f;
auto currentTime = std::chrono::steady_clock::now(); texCoordBuffer[bufferIndex * 2 + 1] = 0.0f;
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
currentTime - lastEmissionTime).count();
if (isActive && elapsed >= emissionRate) { bufferIndex++;
emit(); }
lastEmissionTime = currentTime; }
}
for (auto& particle : particles) { for (size_t i = bufferIndex; i < maxParticles; i++) {
if (particle.active) { positionBuffer[i * 4] = 0.0f;
particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f; positionBuffer[i * 4 + 1] = 0.0f;
particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f; positionBuffer[i * 4 + 2] = 0.0f;
particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f; positionBuffer[i * 4 + 3] = 0.0f;
texCoordBuffer[i * 2] = 0.0f;
texCoordBuffer[i * 2 + 1] = 0.0f;
}
particle.lifeTime += deltaTimeMs; buffersDirty = false;
}
if (particle.lifeTime >= particle.maxLifeTime) { void SparkEmitter::update(float deltaTimeMs) {
particle.active = false; auto currentTime = std::chrono::steady_clock::now();
} auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
currentTime - lastEmissionTime).count();
float lifeRatio = particle.lifeTime / particle.maxLifeTime; if (isActive && elapsed >= emissionRate) {
particle.scale = 1.0f - lifeRatio * 0.8f; emit();
} lastEmissionTime = currentTime;
} }
}
void SparkEmitter::emit() { bool anyChanged = false;
if (emissionPoints.empty()) return; for (auto& particle : particles) {
if (particle.active) {
Vector3f oldPosition = particle.position;
for (int i = 0; i < emissionPoints.size(); ++i) { particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f;
bool particleFound = false; particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f;
particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f;
for (auto& particle : particles) { particle.lifeTime += deltaTimeMs;
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()) { if (particle.lifeTime >= particle.maxLifeTime) {
size_t oldestIndex = 0; particle.active = false;
float maxLifeTime = 0; anyChanged = true;
}
else {
float lifeRatio = particle.lifeTime / particle.maxLifeTime;
particle.scale = 1.0f - lifeRatio * 0.8f;
for (size_t j = 0; j < particles.size(); ++j) { if (oldPosition.v[0] != particle.position.v[0] ||
if (particles[j].lifeTime > maxLifeTime) { oldPosition.v[1] != particle.position.v[1] ||
maxLifeTime = particles[j].lifeTime; oldPosition.v[2] != particle.position.v[2]) {
oldestIndex = j; anyChanged = true;
} }
} }
}
}
initParticle(particles[oldestIndex], i); if (anyChanged) {
particles[oldestIndex].active = true; buffersDirty = true;
particles[oldestIndex].lifeTime = 0; }
particles[oldestIndex].position = emissionPoints[i]; }
particles[oldestIndex].emitterIndex = i;
}
}
}
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) { void SparkEmitter::emit() {
particle.velocity = getRandomVelocity(emitterIndex); if (emissionPoints.empty()) return;
particle.scale = 1.0f; bool emitted = false;
particle.maxLifeTime = 800.0f + (rand() % 400); // От 800 до 1200 мс
particle.emitterIndex = emitterIndex;
}
Vector3f SparkEmitter::getRandomVelocity(int emitterIndex) { for (int i = 0; i < emissionPoints.size(); ++i) {
static std::random_device rd; bool particleFound = false;
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); for (auto& particle : particles) {
float speed = speedDist(gen); if (!particle.active) {
float zSpeed = zSpeedDist(gen); initParticle(particle, i);
particle.active = true;
particle.lifeTime = 0;
particle.position = emissionPoints[i];
particle.emitterIndex = i;
particleFound = true;
emitted = true;
break;
}
}
if (emitterIndex == 0) { if (!particleFound && !particles.empty()) {
return Vector3f{ size_t oldestIndex = 0;
cosf(angle) * speed - 0.3f, float maxLifeTime = 0;
sinf(angle) * speed,
zSpeed
};
}
else {
return Vector3f{
cosf(angle) * speed + 0.3f,
sinf(angle) * speed,
zSpeed
};
}
}
const std::vector<SparkParticle>& SparkEmitter::getParticles() const { for (size_t j = 0; j < particles.size(); ++j) {
return particles; if (particles[j].lifeTime > maxLifeTime) {
} maxLifeTime = particles[j].lifeTime;
oldestIndex = j;
}
}
size_t SparkEmitter::getActiveParticleCount() const { initParticle(particles[oldestIndex], i);
size_t count = 0; particles[oldestIndex].active = true;
for (const auto& particle : particles) { particles[oldestIndex].lifeTime = 0;
if (particle.active) { particles[oldestIndex].position = emissionPoints[i];
count++; particles[oldestIndex].emitterIndex = i;
} emitted = true;
} }
return count; }
}
if (emitted) {
buffersDirty = true;
}
}
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) {
particle.velocity = getRandomVelocity(emitterIndex);
particle.scale = 1.0f;
particle.maxLifeTime = 800.0f + (rand() % 400);
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;
}
size_t SparkEmitter::getActiveParticleBufferIndex(size_t particleIndex) const {
size_t activeIndex = 0;
for (size_t i = 0; i <= particleIndex; i++) {
if (particles[i].active) {
if (i == particleIndex) return activeIndex;
activeIndex++;
}
}
return 0;
}
} // namespace ZL } // namespace ZL

View File

@ -6,45 +6,56 @@
namespace ZL { namespace ZL {
struct SparkParticle { struct SparkParticle {
Vector3f position; Vector3f position;
Vector3f velocity; Vector3f velocity;
float scale; float scale;
float lifeTime; float lifeTime;
float maxLifeTime; float maxLifeTime;
bool active; bool active;
int emitterIndex; int emitterIndex;
Vector2f texCoord;
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f), SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) { lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
} }
}; };
class SparkEmitter { class SparkEmitter {
private: private:
std::vector<SparkParticle> particles; std::vector<SparkParticle> particles;
std::vector<Vector3f> emissionPoints; std::vector<Vector3f> emissionPoints;
std::chrono::steady_clock::time_point lastEmissionTime; std::chrono::steady_clock::time_point lastEmissionTime;
float emissionRate; float emissionRate;
bool isActive; bool isActive;
public: std::vector<float> positionBuffer;
SparkEmitter(); std::vector<float> texCoordBuffer;
SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f); bool buffersDirty;
int maxParticles;
void setEmissionPoints(const std::vector<Vector3f>& positions); public:
void setEmissionRate(float rateMs); SparkEmitter();
void setActive(bool active); SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f);
void update(float deltaTimeMs); void setEmissionPoints(const std::vector<Vector3f>& positions);
void emit();
const std::vector<SparkParticle>& getParticles() const; void update(float deltaTimeMs);
size_t getActiveParticleCount() const; void emit();
private: const std::vector<SparkParticle>& getParticles() const;
void initParticle(SparkParticle& particle, int emitterIndex); size_t getActiveParticleCount() const;
Vector3f getRandomVelocity(int emitterIndex);
}; const float* getPositionBuffer() const { return positionBuffer.data(); }
const float* getTexCoordBuffer() const { return texCoordBuffer.data(); }
size_t getBufferSize() const { return positionBuffer.size() / 4; }
void updateBuffers();
size_t getActiveParticleBufferIndex(size_t particleIndex) const;
private:
void initParticle(SparkParticle& particle, int emitterIndex);
Vector3f getRandomVelocity(int emitterIndex);
};
} // namespace ZL } // namespace ZL