osb/source/game/StarParticleManager.cpp
2023-06-20 14:33:09 +10:00

116 lines
3.3 KiB
C++

#include "StarParticleManager.hpp"
#include "StarIterator.hpp"
#include "StarLogging.hpp"
namespace Star {
ParticleManager::ParticleManager(WorldGeometry const& worldGeometry, ClientTileSectorArrayPtr const& tileSectorArray)
: m_worldGeometry(worldGeometry), m_undergroundLevel(0.0f), m_tileSectorArray(tileSectorArray) {}
void ParticleManager::add(Particle particle) {
m_particles.push_back(move(particle));
}
void ParticleManager::addParticles(List<Particle> particles) {
m_particles.appendAll(move(particles));
}
size_t ParticleManager::count() const {
return m_particles.size();
}
void ParticleManager::clear() {
m_particles.clear();
}
void ParticleManager::setUndergroundLevel(float undergroundLevel) {
m_undergroundLevel = undergroundLevel;
}
void ParticleManager::update(float dt, RectF const& cullRegion, float wind) {
if (!m_tileSectorArray)
return;
auto cullRects = m_worldGeometry.splitRect(cullRegion);
for (auto& particle : m_particles) {
bool inRegion = false;
Vec2F worldPos = m_worldGeometry.xwrap(particle.position);
for (auto cullRect : cullRects) {
if (cullRect.contains(worldPos)) {
inRegion = true;
break;
}
}
if (!inRegion)
continue;
particle.update(dt, Vec2F(wind, 0));
Vec2I pos(particle.position.floor());
TileType tiletype;
auto const& tile = m_tileSectorArray->tile(pos);
if (isSolidColliding(tile.collision))
tiletype = TileType::Colliding;
else if (tile.liquid.level > 0.5f)
tiletype = TileType::Water;
else
tiletype = TileType::Empty;
if (particle.collidesForeground && tiletype == TileType::Colliding) {
RectF colRect;
colRect.setXMax(std::ceil(particle.position[0]));
colRect.setXMin(std::floor(particle.position[0]));
colRect.setYMax(std::ceil(particle.position[1]));
colRect.setYMin(std::floor(particle.position[1]));
Line2F colLine(particle.position, particle.position - particle.velocity);
auto collisionPosition = colRect.edgeIntersection(colLine).point;
if (particle.position[0] > colRect.center()[0])
collisionPosition[0] += 0.1f;
else if (particle.position[0] < colRect.center()[0])
collisionPosition[0] -= 0.1f;
if (particle.position[1] > colRect.center()[1])
collisionPosition[1] += 0.1f;
else if (particle.position[1] < colRect.center()[1])
collisionPosition[1] -= 0.1f;
particle.collide(collisionPosition);
}
if (particle.underwaterOnly && tiletype == TileType::Empty)
particle.destroy(false);
if (particle.collidesLiquid && tiletype == TileType::Water)
particle.destroy(false);
if (particle.trail && particle.timeToLive >= 0.0f) {
auto trail = particle;
trail.trail = false;
trail.timeToLive = 0;
trail.velocity = {};
m_nextParticles.append(move(trail));
}
if (!particle.dead())
m_nextParticles.append(move(particle));
}
m_particles.clear();
swap(m_particles, m_nextParticles);
}
List<Particle> const& ParticleManager::particles() const {
return m_particles;
}
List<pair<Vec2F, Vec3B>> ParticleManager::lightSources() const {
List<pair<Vec2F, Vec3B>> lsources;
for (auto const& particle : m_particles) {
if (particle.light != Color::Clear)
lsources.append({particle.position, particle.light.toRgb()});
}
return lsources;
}
}