object/explosion.[ch]pp: Added the "hurt" and "push" members.
authorFlorian Forster <supertux@octo.it>
Tue, 2 Mar 2010 11:25:10 +0000 (11:25 +0000)
committerFlorian Forster <supertux@octo.it>
Tue, 2 Mar 2010 11:25:10 +0000 (11:25 +0000)
If "hurt" is set (true by default), then the explosion will hurt Tux and nearby
badguys. If "push" is set (false by default), Tux and nearby walking badguys
will experience the force of the explosion, possibly throwing them in the air.

SVN-Revision: 6510

src/object/explosion.cpp
src/object/explosion.hpp

index 25a1148..d9e806c 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "audio/sound_manager.hpp"
 #include "badguy/badguy.hpp"
+#include "badguy/walking_badguy.hpp"
 #include "math/random_generator.hpp"
 #include "object/player.hpp"
 #include "object/sprite_particle.hpp"
 
 #include <math.h>
 
-Explosion::Explosion(const Vector& pos)
-  : MovingSprite(pos, "images/objects/explosion/explosion.sprite", LAYER_OBJECTS+40, COLGROUP_MOVING), state(STATE_WAITING)
+Explosion::Explosion(const Vector& pos) :
+  MovingSprite(pos, "images/objects/explosion/explosion.sprite", LAYER_OBJECTS+40, COLGROUP_MOVING),
+  hurt(true),
+  push(false),
+  state(STATE_WAITING)
 {
   sound_manager->preload("sounds/explosion.wav");
   set_pos(get_pos() - (get_bbox().get_middle() - get_pos()));
 }
 
-Explosion::Explosion(const Reader& reader)
-  : MovingSprite(reader, "images/objects/explosion/explosion.sprite", LAYER_OBJECTS+40, COLGROUP_MOVING), state(STATE_WAITING)
+Explosion::Explosion(const Reader& reader) :
+  MovingSprite(reader, "images/objects/explosion/explosion.sprite", LAYER_OBJECTS+40, COLGROUP_MOVING),
+  hurt(true),
+  push(false),
+  state(STATE_WAITING)
 {
   sound_manager->preload("sounds/explosion.wav");
 }
@@ -42,28 +49,63 @@ Explosion::Explosion(const Reader& reader)
 void
 Explosion::explode()
 {
-  if (state != STATE_WAITING) return;
+  if (state != STATE_WAITING)
+    return;
   state = STATE_EXPLODING;
 
   set_action("default", 1);
   sprite->set_animation_loops(1); //TODO: this is necessary because set_action will not set "loops" when "action" is the default action
   sound_manager->play("sounds/explosion.wav", get_pos());
 
-  if (0)
-  {
-    // spawn some particles
-    // TODO: provide convenience function in MovingSprite or MovingObject?
-    for (int i = 0; i < 100; i++) {
-      Vector ppos = bbox.get_middle();
-      float angle = graphicsRandom.randf(-M_PI_2, M_PI_2);
-      float velocity = graphicsRandom.randf(450, 900);
-      float vx = sin(angle)*velocity;
-      float vy = -cos(angle)*velocity;
-      Vector pspeed = Vector(vx, vy);
-      Vector paccel = Vector(0, 1000);
-      Sector::current()->add_object(new SpriteParticle("images/objects/particles/explosion.sprite", "default", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1));
-    }
+#if 0
+  // spawn some particles
+  // TODO: provide convenience function in MovingSprite or MovingObject?
+  for (int i = 0; i < 100; i++) {
+    Vector ppos = bbox.get_middle();
+    float angle = graphicsRandom.randf(-M_PI_2, M_PI_2);
+    float velocity = graphicsRandom.randf(450, 900);
+    float vx = sin(angle)*velocity;
+    float vy = -cos(angle)*velocity;
+    Vector pspeed = Vector(vx, vy);
+    Vector paccel = Vector(0, 1000);
+    Sector::current()->add_object(new SpriteParticle("images/objects/particles/explosion.sprite", "default", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1));
   }
+#endif
+
+  if (push) {
+    Vector center = get_bbox ().get_middle ();
+    std::vector<MovingObject*> near_objects = Sector::current()->get_nearby_objects (center, 10.0 * 32.0);
+
+    for (size_t i = 0; i < near_objects.size (); i++) {
+      MovingObject *obj = near_objects[i];
+      Vector obj_vector = obj->get_bbox ().get_middle ();
+      Vector direction = obj_vector - center;
+      float distance = direction.norm ();
+
+      /* If the distance is very small, for example because "obj" is the badguy
+       * causing the explosion, skip this object. */
+      if (distance <= 1.0)
+        continue;
+
+      /* The force decreases with the distance squared. In the distance of one
+       * tile (32 pixels) you will have a speed increase of 150 pixels/s. */
+      float force = 150.0 * 32.0*32.0 / (distance * distance);
+      if (force > 200.0)
+        force = 200.0;
+
+      Vector add_speed = direction.unit () * force;
+
+      Player *player = dynamic_cast<Player *> (obj);
+      if (player) {
+        player->add_velocity (add_speed);
+      }
+
+      WalkingBadguy *badguy = dynamic_cast<WalkingBadguy *> (obj);
+      if (badguy) {
+        badguy->add_velocity (add_speed);
+      }
+    } /* for (i = 0 ... near_objects) */
+  } /* if (push) */
 }
 
 void 
@@ -84,7 +126,8 @@ Explosion::update(float )
 HitResponse
 Explosion::collision(GameObject& other, const CollisionHit& )
 {
-  if(state != STATE_EXPLODING) return ABORT_MOVE;
+  if ((state != STATE_EXPLODING) || !hurt)
+    return ABORT_MOVE;
 
   Player* player = dynamic_cast<Player*>(&other);
   if(player != 0) {
index 0d556c4..869b982 100644 (file)
@@ -34,6 +34,26 @@ public:
   void update(float elapsed_time);
   HitResponse collision(GameObject& other, const CollisionHit& hit);
 
+  bool hurts (void) const
+  {
+    return this->hurt;
+  }
+
+  void hurts (bool val)
+  {
+    this->hurt = val;
+  }
+
+  bool pushes (void) const
+  {
+    return this->push;
+  }
+
+  void pushes (bool val)
+  {
+    this->push = val;
+  }
+
 protected:
   /**
    * plays sound, starts animation
@@ -45,6 +65,8 @@ private:
     STATE_WAITING,
     STATE_EXPLODING
   };
+  bool hurt;
+  bool push;
   State state;
 
 };