diff options
author | Alec Thomas <alec@swapoff.org> | 2015-04-24 20:43:12 +1000 |
---|---|---|
committer | Alec Thomas <alec@swapoff.org> | 2015-04-24 20:43:12 +1000 |
commit | e69c65d8bed921e312f8fa02b3825a8555499699 (patch) | |
tree | b69d8586935579a798d7e02d88be1086491b9f17 /examples | |
parent | 29d8c3763c27e5cc18695f8261145c836670efd7 (diff) |
Update example with a vertex array-based particle system.
Diffstat (limited to 'examples')
-rw-r--r-- | examples/example.cc | 148 |
1 files changed, 94 insertions, 54 deletions
diff --git a/examples/example.cc b/examples/example.cc index 5b71d90..d611756 100644 --- a/examples/example.cc +++ b/examples/example.cc @@ -63,10 +63,12 @@ struct Renderable { }; -struct Fadeable { - explicit Fadeable(sf::Uint8 alpha, float duration) : alpha(alpha), d(alpha / duration) {} +struct Particle { + explicit Particle(sf::Color colour, float radius, float duration) + : colour(colour), radius(radius), alpha(colour.a), d(colour.a / duration) {} - float alpha, d; + sf::Color colour; + float radius, alpha, d; }; @@ -85,6 +87,40 @@ struct CollisionEvent { }; +class SpawnSystem : public ex::System<SpawnSystem> { +public: + explicit SpawnSystem(sf::RenderTarget &target, int count) : size(target.getSize()), count(count) {} + + void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override { + int c = 0; + ex::ComponentHandle<Collideable> collideable; + for (ex::Entity entity : es.entities_with_components(collideable)) c++; + + for (int i = 0; i < count - c; i++) { + ex::Entity entity = es.create(); + + // Mark as collideable (explosion particles will not be collideable). + collideable = entity.assign<Collideable>(r(10, 5)); + + // "Physical" attributes. + entity.assign<Body>( + sf::Vector2f(r(size.x), r(size.y)), + sf::Vector2f(r(100, -50), r(100, -50))); + + // Shape to apply to entity. + std::unique_ptr<sf::Shape> shape(new sf::CircleShape(collideable->radius)); + shape->setFillColor(sf::Color(r(128, 127), r(128, 127), r(128, 127))); + shape->setOrigin(collideable->radius, collideable->radius); + entity.assign<Renderable>(std::move(shape)); + } + } + +private: + sf::Vector2u size; + int count; +}; + + // Updates a body's position and rotation. struct BodySystem : public ex::System<BodySystem> { void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override { @@ -97,26 +133,6 @@ struct BodySystem : public ex::System<BodySystem> { }; -// Fades out the alpha value of any Renderable and Fadeable entity. Once the -// object has completely faded out it is destroyed. -struct FadeOutSystem : public ex::System<FadeOutSystem> { - void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override { - ex::ComponentHandle<Fadeable> fade; - ex::ComponentHandle<Renderable> renderable; - for (ex::Entity entity : es.entities_with_components(fade, renderable)) { - fade->alpha -= fade->d * dt; - if (fade->alpha <= 0) { - entity.destroy(); - } else { - sf::Color color = renderable->shape->getFillColor(); - color.a = fade->alpha; - renderable->shape->setFillColor(color); - } - } - } -}; - - // Bounce bodies off the edge of the screen. class BounceSystem : public ex::System<BounceSystem> { public: @@ -220,6 +236,44 @@ private: }; +class ParticleSystem : public ex::System<ParticleSystem> { +public: + void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override { + ex::ComponentHandle<Particle> particle; + for (ex::Entity entity : es.entities_with_components(particle)) { + particle->alpha -= particle->d * dt; + if (particle->alpha <= 0) { + entity.destroy(); + } else { + particle->colour.a = particle->alpha; + } + } + } +}; + + +class ParticleRenderSystem : public ex::System<ParticleRenderSystem> { +public: + explicit ParticleRenderSystem(sf::RenderTarget &target) : target(target) {} + + void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override { + sf::VertexArray vertices(sf::Quads); + ex::ComponentHandle<Particle> particle; + ex::ComponentHandle<Body> body; + for (ex::Entity entity : es.entities_with_components(body, particle)) { + float r = particle->radius; + vertices.append(sf::Vertex(body->position + sf::Vector2f(-r, -r), particle->colour)); + vertices.append(sf::Vertex(body->position + sf::Vector2f(r, -r), particle->colour)); + vertices.append(sf::Vertex(body->position + sf::Vector2f(r, r), particle->colour)); + vertices.append(sf::Vertex(body->position + sf::Vector2f(-r, r), particle->colour)); + } + target.draw(vertices); + } +private: + sf::RenderTarget ⌖ +}; + + // For any two colliding bodies, destroys the bodies and emits a bunch of bodgy explosion particles. class ExplosionSystem : public ex::System<ExplosionSystem>, public ex::Receiver<ExplosionSystem> { public: @@ -249,18 +303,15 @@ public: float rotationd = r(720, 180); if (std::rand() % 2 == 0) rotationd = -rotationd; + float offset = r(collideable->radius, 1); + float angle = r(360) * M_PI / 180.0; particle.assign<Body>( - body->position + sf::Vector2f(r(collideable->radius * 2, -collideable->radius), r(collideable->radius * 2, -collideable->radius)), - body->direction + sf::Vector2f(r(50, -25), r(100, -50)), + body->position + sf::Vector2f(offset * cos(angle), offset * sin(angle)), + body->direction + sf::Vector2f(offset * 2 * cos(angle), offset * 2 * sin(angle)), rotationd); float radius = r(3, 1); - std::unique_ptr<sf::Shape> shape(new sf::RectangleShape(sf::Vector2f(radius * 2, radius * 2))); - shape->setFillColor(colour); - shape->setOrigin(radius, radius); - particle.assign<Renderable>(std::move(shape)); - - particle.assign<Fadeable>(colour.a, radius / 2); + particle.assign<Particle>(colour, radius, radius / 2); } } @@ -295,17 +346,21 @@ public: target.draw(*renderable->shape.get()); } last_update += dt; + frame_count++; if (last_update >= 0.5) { std::ostringstream out; - out << es.size() << " entities (" << static_cast<int>(1.0 / dt) << " fps)"; + const double fps = frame_count / last_update; + out << es.size() << " entities (" << static_cast<int>(fps) << " fps)"; text.setString(out.str()); last_update = 0.0; + frame_count = 0.0; } target.draw(text); } private: - float last_update = 0.0; + double last_update = 0.0; + double frame_count = 0.0; sf::RenderTarget ⌖ sf::Text text; }; @@ -314,41 +369,26 @@ private: class Application : public ex::EntityX { public: explicit Application(sf::RenderTarget &target, sf::Font &font) { + systems.add<SpawnSystem>(target, 500); systems.add<BodySystem>(); - systems.add<FadeOutSystem>(); systems.add<BounceSystem>(target); systems.add<CollisionSystem>(target); systems.add<ExplosionSystem>(); + systems.add<ParticleSystem>(); systems.add<RenderSystem>(target, font); + systems.add<ParticleRenderSystem>(target); systems.configure(); - - sf::Vector2u size = target.getSize(); - for (int i = 0; i < 500; i++) { - ex::Entity entity = entities.create(); - - // Mark as collideable (explosion particles will not be collideable). - ex::ComponentHandle<Collideable> collideable = entity.assign<Collideable>(r(10, 5)); - - // "Physical" attributes. - entity.assign<Body>( - sf::Vector2f(r(size.x), r(size.y)), - sf::Vector2f(r(100, -50), r(100, -50))); - - // Shape to apply to entity. - std::unique_ptr<sf::Shape> shape(new sf::CircleShape(collideable->radius)); - shape->setFillColor(sf::Color(r(128, 127), r(128, 127), r(128, 127))); - shape->setOrigin(collideable->radius, collideable->radius); - entity.assign<Renderable>(std::move(shape)); - } } void update(ex::TimeDelta dt) { + systems.update<SpawnSystem>(dt); systems.update<BodySystem>(dt); - systems.update<FadeOutSystem>(dt); systems.update<BounceSystem>(dt); systems.update<CollisionSystem>(dt); systems.update<ExplosionSystem>(dt); + systems.update<ParticleSystem>(dt); systems.update<RenderSystem>(dt); + systems.update<ParticleRenderSystem>(dt); } }; |