fix spark
This commit is contained in:
parent
b855cff0e6
commit
115cbbb7fa
90
Game.h
90
Game.h
@ -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
|
||||||
296
SparkEmitter.cpp
296
SparkEmitter.cpp
@ -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
|
||||||
@ -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
|
||||||
Loading…
Reference in New Issue
Block a user