add particles collision detection
This commit is contained in:
parent
1974298c82
commit
b944f257f7
@ -15,7 +15,8 @@ Emitter::Emitter(
|
||||
prototype(std::move(prototype)),
|
||||
texture(texture),
|
||||
spawnInterval(spawnInterval),
|
||||
count(count) {
|
||||
count(count),
|
||||
behaviour() {
|
||||
this->prototype.emitter = this;
|
||||
}
|
||||
|
||||
@ -37,6 +38,7 @@ void Emitter::update(float delta, std::vector<Particle>& particles) {
|
||||
while (count && timer > spawnInterval) {
|
||||
// spawn particle
|
||||
Particle particle = prototype;
|
||||
particle.emitter = this;
|
||||
particle.position = position;
|
||||
particle.velocity += glm::ballRand(1.0f) * explosion;
|
||||
particles.push_back(std::move(particle));
|
||||
|
||||
@ -26,6 +26,11 @@ struct Particle {
|
||||
|
||||
class Texture;
|
||||
|
||||
struct ParticleBehaviour {
|
||||
bool collision = true;
|
||||
glm::vec3 gravity {0.0f, -16.0f, 0.0f};
|
||||
};
|
||||
|
||||
class Emitter {
|
||||
/// @brief Static position or entity
|
||||
std::variant<glm::vec3, entityid_t> origin;
|
||||
@ -42,8 +47,10 @@ class Emitter {
|
||||
/// to spawn on update. May be innacurate.
|
||||
float timer = 0.0f;
|
||||
/// @brief Random velocity magnitude applying to spawned particles
|
||||
glm::vec3 explosion {1.0f};
|
||||
glm::vec3 explosion {8.0f};
|
||||
public:
|
||||
ParticleBehaviour behaviour;
|
||||
|
||||
Emitter(
|
||||
std::variant<glm::vec3, entityid_t> origin,
|
||||
Particle prototype,
|
||||
@ -52,6 +59,8 @@ public:
|
||||
int count
|
||||
);
|
||||
|
||||
explicit Emitter(const Emitter&) = delete;
|
||||
|
||||
/// @return Emitter particles texture
|
||||
const Texture* getTexture() const;
|
||||
|
||||
|
||||
@ -6,22 +6,38 @@
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "graphics/render/MainBatch.hpp"
|
||||
#include "window/Camera.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
|
||||
size_t ParticlesRenderer::visibleParticles = 0;
|
||||
size_t ParticlesRenderer::aliveEmitters = 0;
|
||||
|
||||
ParticlesRenderer::ParticlesRenderer(const Assets& assets)
|
||||
: batch(std::make_unique<MainBatch>(1024)) {
|
||||
ParticlesRenderer::ParticlesRenderer(const Assets& assets, const Level& level)
|
||||
: batch(std::make_unique<MainBatch>(1024)), level(level) {
|
||||
|
||||
auto region = util::get_texture_region(assets, "blocks:grass_side", "");
|
||||
Emitter emitter(glm::vec3(0, 100, 0), Particle {
|
||||
auto region = util::get_texture_region(assets, "blocks:bazalt", "");
|
||||
emitters.push_back(std::make_unique<Emitter>(glm::vec3(0, 100, 0), Particle {
|
||||
nullptr, glm::vec3(), glm::vec3(), 5.0f, region.region
|
||||
},region.texture, 0.001f, 1000);
|
||||
emitters.push_back(std::make_unique<Emitter>(emitter));
|
||||
},region.texture, 0.002f, -1));
|
||||
}
|
||||
|
||||
ParticlesRenderer::~ParticlesRenderer() = default;
|
||||
|
||||
static inline void update_particle(
|
||||
Particle& particle, float delta, const Chunks& chunks
|
||||
) {
|
||||
const auto& behave = particle.emitter->behaviour;
|
||||
auto& pos = particle.position;
|
||||
auto& vel = particle.velocity;
|
||||
|
||||
vel += delta * behave.gravity;
|
||||
if (behave.collision && chunks.isObstacleAt(pos + vel * delta)) {
|
||||
vel *= 0.0f;
|
||||
}
|
||||
pos += vel * delta;
|
||||
particle.lifetime -= delta;
|
||||
}
|
||||
|
||||
void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
||||
const auto& right = camera.right;
|
||||
const auto& up = camera.up;
|
||||
@ -41,7 +57,7 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
||||
while (iter != vec.end()) {
|
||||
auto& particle = *iter;
|
||||
|
||||
particle.position += particle.velocity * delta;
|
||||
update_particle(particle, delta, *level.chunks);
|
||||
|
||||
batch->quad(
|
||||
particle.position,
|
||||
@ -52,8 +68,6 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
||||
glm::vec3(1.0f),
|
||||
particle.region
|
||||
);
|
||||
|
||||
particle.lifetime -= delta;
|
||||
if (particle.lifetime <= 0.0f) {
|
||||
iter = vec.erase(iter);
|
||||
} else {
|
||||
|
||||
@ -10,15 +10,17 @@ class Texture;
|
||||
class Assets;
|
||||
class Camera;
|
||||
class MainBatch;
|
||||
class Level;
|
||||
|
||||
class ParticlesRenderer {
|
||||
const Level& level;
|
||||
std::unordered_map<const Texture*, std::vector<Particle>> particles;
|
||||
std::vector<std::unique_ptr<Emitter>> emitters;
|
||||
std::unique_ptr<MainBatch> batch;
|
||||
|
||||
void renderParticles(const Camera& camera, float delta);
|
||||
public:
|
||||
ParticlesRenderer(const Assets& assets);
|
||||
ParticlesRenderer(const Assets& assets, const Level& level);
|
||||
~ParticlesRenderer();
|
||||
|
||||
void render(const Camera& camera, float delta);
|
||||
|
||||
@ -62,8 +62,9 @@ WorldRenderer::WorldRenderer(
|
||||
level->chunks.get(),
|
||||
&engine->getSettings()
|
||||
)),
|
||||
particles(std::make_unique<ParticlesRenderer>(*engine->getAssets())) {
|
||||
|
||||
particles(std::make_unique<ParticlesRenderer>(
|
||||
*engine->getAssets(), *frontend->getLevel()
|
||||
)) {
|
||||
renderer = std::make_unique<ChunksRenderer>(
|
||||
level, frontend->getContentGfxCache(), &engine->getSettings()
|
||||
);
|
||||
|
||||
@ -61,10 +61,10 @@ voxel* Chunks::get(int32_t x, int32_t y, int32_t z) const {
|
||||
return &chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
||||
}
|
||||
|
||||
const AABB* Chunks::isObstacleAt(float x, float y, float z) {
|
||||
int ix = floor(x);
|
||||
int iy = floor(y);
|
||||
int iz = floor(z);
|
||||
const AABB* Chunks::isObstacleAt(float x, float y, float z) const {
|
||||
int ix = std::floor(x);
|
||||
int iy = std::floor(y);
|
||||
int iz = std::floor(z);
|
||||
voxel* v = get(ix, iy, iz);
|
||||
if (v == nullptr) {
|
||||
if (iy >= CHUNK_H) {
|
||||
@ -172,8 +172,9 @@ Chunk* Chunks::getChunk(int x, int z) {
|
||||
}
|
||||
|
||||
glm::ivec3 Chunks::seekOrigin(
|
||||
glm::ivec3 pos, const Block& def, blockstate state
|
||||
) {
|
||||
const glm::ivec3& srcpos, const Block& def, blockstate state
|
||||
) const {
|
||||
auto pos = srcpos;
|
||||
const auto& rotation = def.rotations.variants[state.rotation];
|
||||
auto segment = state.segment;
|
||||
while (true) {
|
||||
|
||||
@ -69,7 +69,9 @@ public:
|
||||
/// @param def segment block definition
|
||||
/// @param state segment block state
|
||||
/// @return origin block position or `pos` if block is not extended
|
||||
glm::ivec3 seekOrigin(glm::ivec3 pos, const Block& def, blockstate state);
|
||||
glm::ivec3 seekOrigin(
|
||||
const glm::ivec3& pos, const Block& def, blockstate state
|
||||
) const;
|
||||
|
||||
/// @brief Check if required zone is replaceable
|
||||
/// @param def definition of the block that requires a replaceable zone
|
||||
@ -97,7 +99,12 @@ public:
|
||||
|
||||
glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist);
|
||||
|
||||
const AABB* isObstacleAt(float x, float y, float z);
|
||||
const AABB* isObstacleAt(float x, float y, float z) const;
|
||||
|
||||
const AABB* isObstacleAt(const glm::vec3& pos) const {
|
||||
return isObstacleAt(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
bool isSolidBlock(int32_t x, int32_t y, int32_t z);
|
||||
bool isReplaceableBlock(int32_t x, int32_t y, int32_t z);
|
||||
bool isObstacleBlock(int32_t x, int32_t y, int32_t z);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user