]> code.bitgloo.com Git - clyne/entityx.git/commitdiff
Update example with a vertex array-based particle system.
authorAlec Thomas <alec@swapoff.org>
Fri, 24 Apr 2015 10:43:12 +0000 (20:43 +1000)
committerAlec Thomas <alec@swapoff.org>
Fri, 24 Apr 2015 10:43:12 +0000 (20:43 +1000)
examples/example.cc

index 5b71d90523fe98c31bae83b24f1804bdee62dff8..d611756da6ed2a197385e31ffb0c60fc4e4b3f3d 100644 (file)
@@ -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 &target;
+};
+
+
 // 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 &target;
   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);
   }
 };