added new class for particle systems that need absolute coordinates (currently only...
authorMarek Moeckel <wansti@gmx.de>
Sat, 14 May 2005 13:19:53 +0000 (13:19 +0000)
committerMarek Moeckel <wansti@gmx.de>
Sat, 14 May 2005 13:19:53 +0000 (13:19 +0000)
improved rain, fixed some bugs, created some new ones :)

SVN-Revision: 2482

data/images/sprites.strf
src/object/particlesystem.cpp
src/object/particlesystem.h
src/object/particlesystem_absolute.cpp [new file with mode: 0644]
src/object/particlesystem_absolute.h [new file with mode: 0644]
src/sector.cpp

index 56211ab..7e785de 100644 (file)
     (action
       (images "objects/unstable_tile/unstable_tile.png"))
   )
+  
+  (sprite (name "rainsplash")
+    (action
+      (images "objects/particles/rainsplash-1.png"
+              "objects/particles/rainsplash-2.png"
+              "objects/particles/rainsplash-3.png"
+              "objects/particles/rainsplash-4.png")
+    )
+  )
 
   (sprite (name "worldmaptux")
     (action
index f3e518e..e0500f8 100644 (file)
 #include "resources.h"
 #include "main.h"
 
-#include "tile.h"
-#include "tilemap.h"
-#include "math/aatriangle.h"
-#include "collision.h"
-#include "collision_hit.h"
-#include "object/camera.h"
-
-
 ParticleSystem::ParticleSystem()
 {
     virtual_width = SCREEN_WIDTH;
@@ -137,124 +129,6 @@ void SnowParticleSystem::update(float elapsed_time)
     }
 }
 
-RainParticleSystem::RainParticleSystem()
-{
-    rainimages[0] = new Surface(datadir+"/images/objects/particles/rain0.png", true);
-    rainimages[1] = new Surface(datadir+"/images/objects/particles/rain1.png", true);
-
-    virtual_width = SCREEN_WIDTH * 2;
-
-    // create some random raindrops
-    size_t raindropcount = size_t(virtual_width/8.0);
-    for(size_t i=0; i<raindropcount; ++i) {
-        RainParticle* particle = new RainParticle;
-        particle->pos.x = rand() % int(virtual_width);
-        particle->pos.y = rand() % int(virtual_height);
-        int rainsize = rand() % 2;
-        particle->texture = rainimages[rainsize];
-        do {
-            particle->speed = (rainsize+1)*45 + (float(rand()%10)*.4);
-        } while(particle->speed < 1);
-        particle->speed *= 10; // gravity
-
-        particles.push_back(particle);
-    }
-}
-
-void
-RainParticleSystem::parse(const lisp::Lisp& reader)
-{
-  reader.get("layer", layer);
-}
-
-void
-RainParticleSystem::write(lisp::Writer& writer)
-{
-  writer.start_list("particles-rain");
-  writer.write_int("layer", layer);
-  writer.end_list("particles-rain");
-}
-
-RainParticleSystem::~RainParticleSystem()
-{
-  for(int i=0;i<2;++i)
-    delete rainimages[i];
-}
-
-void RainParticleSystem::update(float elapsed_time)
-{
-    std::vector<Particle*>::iterator i;
-    for(
-        i = particles.begin(); i != particles.end(); ++i) {
-        RainParticle* particle = (RainParticle*) *i;
-        float movement = particle->speed * elapsed_time;
-        particle->pos.y += movement;
-        particle->pos.x -= movement;
-        if ((particle->pos.y > SCREEN_HEIGHT) || (collision(particle, Vector(-movement, movement)))) {
-            particle->pos.y = Sector::current()->camera->get_translation().y;
-            particle->pos.x = rand() % int(virtual_width);
-        }
-    }
-}
-
-bool
-RainParticleSystem::collision(RainParticle* object, Vector movement)
-{
-  TileMap* solids = Sector::current()->solids;
-  // calculate rectangle where the object will move
-  float x1, x2;
-  float y1, y2;
-  x1 = object->pos.x;
-  x2 = x1 + 32 + movement.x;
-  y1 = object->pos.y;
-  y2 = y1 + 32 + movement.y;
-  
-  // test with all tiles in this rectangle
-  int starttilex = int(x1-1) / 32;
-  int starttiley = int(y1-1) / 32;
-  int max_x = int(x2+1);
-  int max_y = int(y2+1);
-
-  CollisionHit temphit, hit;
-  Rect dest = Rect(x1, y1, x2, y2);
-  dest.move(movement);
-  hit.time = -1; // represents an invalid value
-  for(int x = starttilex; x*32 < max_x; ++x) {
-    for(int y = starttiley; y*32 < max_y; ++y) {
-      const Tile* tile = solids->get_tile(x, y);
-      if(!tile)
-        continue;
-      // skip non-solid tiles
-      if(!(tile->getAttributes() & Tile::SOLID))
-        continue;
-
-      if(tile->getAttributes() & Tile::SLOPE) { // slope tile
-        AATriangle triangle;
-        Vector p1(x*32, y*32);
-        Vector p2((x+1)*32, (y+1)*32);
-        triangle = AATriangle(p1, p2, tile->getData());
-
-        if(Collision::rectangle_aatriangle(temphit, dest, movement,
-              triangle)) {
-          if(temphit.time > hit.time)
-            hit = temphit;
-        }
-      } else { // normal rectangular tile
-        Rect rect(x*32, y*32, (x+1)*32, (y+1)*32);
-        if(Collision::rectangle_rectangle(temphit, dest,
-              movement, rect)) {
-          if(temphit.time > hit.time)
-            hit = temphit;
-        }
-      }
-    }
-  }
-  
-  // did we collide at all?
-  if(hit.time < 0)
-    return false; else return true;
-}
-
 CloudParticleSystem::CloudParticleSystem()
 {
     cloudimage = new Surface(datadir + "/images/objects/particles/cloud.png", true);
index dde5f87..05dd9f3 100644 (file)
@@ -97,31 +97,6 @@ private:
     Surface* snowimages[3];
 };
 
-class RainParticleSystem : public ParticleSystem, public Serializable
-{
-public:
-    RainParticleSystem();
-    virtual ~RainParticleSystem();
-
-    void parse(const lisp::Lisp& lisp);
-    void write(lisp::Writer& writer);
-
-    virtual void update(float elapsed_time);
-
-    std::string type() const
-    { return "RainParticleSystem"; }
-    
-private:
-    class RainParticle : public Particle
-    {
-    public:
-        float speed;
-    };
-    
-    bool collision(RainParticle* particle, Vector movement);
-    Surface* rainimages[2];
-};
-
 class CloudParticleSystem : public ParticleSystem, public Serializable
 {
 public:
diff --git a/src/object/particlesystem_absolute.cpp b/src/object/particlesystem_absolute.cpp
new file mode 100644 (file)
index 0000000..95e1ae5
--- /dev/null
@@ -0,0 +1,204 @@
+//  $Id: particlesystem.cpp 2470 2005-05-11 14:49:28Z wansti $
+// 
+//  SuperTux
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include <iostream>
+#include <cmath>
+
+#include "particlesystem_absolute.h"
+#include "video/drawing_context.h"
+#include "lisp/parser.h"
+#include "lisp/lisp.h"
+#include "lisp/writer.h"
+#include "resources.h"
+#include "main.h"
+
+#include "tile.h"
+#include "tilemap.h"
+#include "math/aatriangle.h"
+#include "collision.h"
+#include "collision_hit.h"
+#include "object/camera.h"
+
+//TODO: Try to equally distribute rain throughout the level
+//      Dynamically create splashes at collision spots
+//      Check why it can rain through boxes
+//      Add an option to set rain strength
+ParticleSystem_Absolute::ParticleSystem_Absolute()
+{
+    virtual_width = SCREEN_WIDTH;
+    virtual_height = SCREEN_HEIGHT;
+    layer = LAYER_BACKGROUND1;
+}
+
+ParticleSystem_Absolute::~ParticleSystem_Absolute()
+{
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        delete *i;
+    }
+}
+
+void ParticleSystem_Absolute::draw(DrawingContext& context)
+{
+  //float scrollx = context.get_translation().x;
+  //float scrolly = context.get_translation().y;
+
+  context.push_transform();
+  //context.set_translation(Vector(0,0));
+  
+    std::vector<Particle*>::iterator i;
+    for(i = particles.begin(); i != particles.end(); ++i) {
+        Particle* particle = *i;
+
+        // remap x,y coordinates onto screencoordinates
+        /*Vector pos;
+        pos.x = fmodf(particle->pos.x - scrollx, virtual_width);
+        if(pos.x < 0) pos.x += virtual_width;
+        pos.y = fmodf(particle->pos.y - scrolly, virtual_height);
+        if(pos.y < 0) pos.y += virtual_height;
+
+        if(pos.x > SCREEN_WIDTH) pos.x -= virtual_width;
+        if(pos.y > SCREEN_HEIGHT) pos.y -= virtual_height;*/
+        context.draw_surface(particle->texture, particle->pos, layer);
+    }
+
+    context.pop_transform();
+}
+
+RainParticleSystem::RainParticleSystem()
+{
+    rainimages[0] = new Surface(datadir+"/images/objects/particles/rain0.png", true);
+    rainimages[1] = new Surface(datadir+"/images/objects/particles/rain1.png", true);
+
+    virtual_width = SCREEN_WIDTH * 2;
+
+    // create some random raindrops
+    size_t raindropcount = size_t(virtual_width/4.0);
+    for(size_t i=0; i<raindropcount; ++i) {
+        RainParticle* particle = new RainParticle;
+        particle->pos.x = rand() % int(virtual_width);
+        particle->pos.y = rand() % int(virtual_height);
+        int rainsize = rand() % 2;
+        particle->texture = rainimages[rainsize];
+        do {
+            particle->speed = (rainsize+1)*45 + (float(rand()%10)*.4);
+        } while(particle->speed < 1);
+        particle->speed *= 10; // gravity
+
+        particles.push_back(particle);
+    }
+}
+
+void
+RainParticleSystem::parse(const lisp::Lisp& reader)
+{
+  reader.get("layer", layer);
+}
+
+void
+RainParticleSystem::write(lisp::Writer& writer)
+{
+  writer.start_list("particles-rain");
+  writer.write_int("layer", layer);
+  writer.end_list("particles-rain");
+}
+
+RainParticleSystem::~RainParticleSystem()
+{
+  for(int i=0;i<2;++i)
+    delete rainimages[i];
+}
+
+void RainParticleSystem::update(float elapsed_time)
+{
+    std::vector<Particle*>::iterator i;
+    for(
+        i = particles.begin(); i != particles.end(); ++i) {
+        RainParticle* particle = (RainParticle*) *i;
+        float movement = particle->speed * elapsed_time;
+        float abs_x = Sector::current()->camera->get_translation().x;
+        float abs_y = Sector::current()->camera->get_translation().y;
+        particle->pos.y += movement;
+        particle->pos.x -= movement;
+        if ((particle->pos.y > SCREEN_HEIGHT + abs_y) || (collision(particle, Vector(-movement, movement)))) {
+            particle->pos.y = 0;
+            particle->pos.x = rand() % int(abs_x + virtual_width);
+        }
+    }
+}
+
+bool
+RainParticleSystem::collision(RainParticle* object, Vector movement)
+{
+  TileMap* solids = Sector::current()->solids;
+  // calculate rectangle where the object will move
+  float x1, x2;
+  float y1, y2;
+  x1 = object->pos.x;
+  x2 = x1 + 32 + movement.x;
+  y1 = object->pos.y;
+  y2 = y1 + 32 + movement.y;
+  
+  // test with all tiles in this rectangle
+  int starttilex = int(x1-1) / 32;
+  int starttiley = int(y1-1) / 32;
+  int max_x = int(x2+1);
+  int max_y = int(y2+1);
+  
+  CollisionHit temphit, hit;
+  Rect dest = Rect(x1, y1, x2, y2);
+  dest.move(movement);
+  hit.time = -1; // represents an invalid value
+  for(int x = starttilex; x*32 < max_x; ++x) {
+    for(int y = starttiley; y*32 < max_y; ++y) {
+      const Tile* tile = solids->get_tile(x, y);
+      //std::cout << "Tile at: " << x << "," << y << std::endl;
+      if(!tile)
+        continue;
+      // skip non-solid tiles
+      if(!(tile->getAttributes() & Tile::SOLID))
+        continue;
+
+      if(tile->getAttributes() & Tile::SLOPE) { // slope tile
+        AATriangle triangle;
+        Vector p1(x*32, y*32);
+        Vector p2((x+1)*32, (y+1)*32);
+        triangle = AATriangle(p1, p2, tile->getData());
+
+        if(Collision::rectangle_aatriangle(temphit, dest, movement,
+              triangle)) {
+          if(temphit.time > hit.time)
+            hit = temphit;
+        }
+      } else { // normal rectangular tile
+        Rect rect(x*32, y*32, (x+1)*32, (y+1)*32);
+        if(Collision::rectangle_rectangle(temphit, dest,
+              movement, rect)) {
+          if(temphit.time > hit.time)
+            hit = temphit;
+        }
+      }
+    }
+  }
+  
+  // did we collide at all?
+  if(hit.time < 0)
+    return false; else return true;
+}
diff --git a/src/object/particlesystem_absolute.h b/src/object/particlesystem_absolute.h
new file mode 100644 (file)
index 0000000..1a3d137
--- /dev/null
@@ -0,0 +1,102 @@
+//  $Id: ParticleSystem_Absolute.h 2462 2005-05-10 15:38:16Z wansti $
+// 
+//  SuperTux
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_PARTICLESYSTEM_ABSOLUTE_H
+#define SUPERTUX_PARTICLESYSTEM_ABSOLUTE_H
+
+#include <vector>
+
+#include "video/surface.h"
+#include "game_object.h"
+#include "serializable.h"
+#include "sector.h"
+#include "math/vector.h"
+
+namespace lisp {
+class Lisp;
+}
+
+class DisplayManager;
+
+/**
+ * This is the base class for particle systems. It is responsible for storing a
+ * set of particles with each having an x- and y-coordinate the number of the
+ * layer where it should be drawn and a texture.
+ * The coordinate system used here is a virtual one. It would be a bad idea to
+ * populate whole levels with particles. So we're using a virtual rectangle
+ * here that is tiled onto the level when drawing. This rect.has the size
+ * (virtual_width, virtual_height). We're using modulo on the particle
+ * coordinates, so when a particle leaves left, it'll reenter at the right
+ * side.
+ *
+ * Classes that implement a particle system should subclass from this class,
+ * initialize particles in the constructor and move them in the simulate
+ * function.
+ */
+class ParticleSystem_Absolute : public GameObject
+{
+public:
+    ParticleSystem_Absolute();
+    virtual ~ParticleSystem_Absolute();
+    
+    virtual void draw(DrawingContext& context);
+
+protected:
+    int layer;
+
+    class Particle
+    {
+    public:
+        virtual ~Particle()
+        { }
+
+        Vector pos;
+        Surface* texture;
+    };
+    
+    std::vector<Particle*> particles;
+    float virtual_width, virtual_height;
+};
+
+class RainParticleSystem : public ParticleSystem_Absolute, public Serializable
+{
+public:
+    RainParticleSystem();
+    virtual ~RainParticleSystem();
+
+    void parse(const lisp::Lisp& lisp);
+    void write(lisp::Writer& writer);
+
+    virtual void update(float elapsed_time);
+
+    std::string type() const
+    { return "RainParticleSystem"; }
+    
+private:
+    class RainParticle : public Particle
+    {
+    public:
+        float speed;
+    };
+    
+    bool collision(RainParticle* particle, Vector movement);
+    Surface* rainimages[2];
+};
+
+#endif
+
index 8a53d05..d911c4a 100644 (file)
@@ -32,6 +32,7 @@
 #include "object/camera.h"
 #include "object/background.h"
 #include "object/particlesystem.h"
+#include "object/particlesystem_absolute.h"
 #include "object/tilemap.h"
 #include "lisp/parser.h"
 #include "lisp/lisp.h"