some cleanups in the sprite class, increased delta for collision response
authorMatthias Braun <matze@braunis.de>
Wed, 24 Nov 2004 23:10:09 +0000 (23:10 +0000)
committerMatthias Braun <matze@braunis.de>
Wed, 24 Nov 2004 23:10:09 +0000 (23:10 +0000)
SVN-Revision: 2177

16 files changed:
TODO
lib/app/setup.cpp
lib/app/tinygettext.cpp
lib/app/tinygettext.h
lib/special/collision_hit.h
lib/special/sprite.cpp
lib/special/sprite.h
src/badguy/badguy.cpp
src/badguy/dispenser.cpp
src/object/block.cpp
src/object/coin.cpp
src/object/coin.h
src/player.cpp
src/player.h
src/sector.cpp
src/trigger/door.cpp

diff --git a/TODO b/TODO
index 21b90ac..37ab3ba 100644 (file)
--- a/TODO
+++ b/TODO
@@ -110,6 +110,7 @@ L: low priority
     themselfes. This could speed up rendering of tilemaps.
 [H] implement quadtree to speed up collision detection
 [?] remove badguyspecs and bitmask files
+[M] Make the gamelogic run in a fixed logical framerate
 
 --Miscellaneous--
 [?] think about how to implement scripting, and how to make a simple and easy to
index fb41e0f..20de542 100644 (file)
@@ -262,6 +262,7 @@ void Setup::init(const std::string& _package_name,
     
   directories();
   dictionary_manager.add_directory(datadir + "/locale");
+  dictionary_manager.set_charset("iso8859-1");
 }
 
 /* --- SETUP --- */
index abaa48a..fb88278 100644 (file)
@@ -237,6 +237,8 @@ DictionaryManager::get_dictionary(const std::string& spec)
       Dictionary& dict = dictionaries[lang];
 
       dict.set_language(get_language_def(lang));
+      if(charset != "")
+        dict.set_charset(charset);
 
       for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
         {
@@ -309,6 +311,14 @@ DictionaryManager::set_language(const std::string& lang)
 }
 
 void
+DictionaryManager::set_charset(const std::string& charset)
+{
+  dictionaries.clear(); // changing charset invalidates cache
+  this->charset = charset;
+  set_language(language);
+}
+
+void
 DictionaryManager::set_language_alias(const std::string& alias,
     const std::string& language)
 {
@@ -334,9 +344,8 @@ DictionaryManager::get_language_from_spec(const std::string& spec)
 void
 DictionaryManager::add_directory(const std::string& pathname)
 {
+  dictionaries.clear(); // adding directories invalidates cache
   search_path.push_back(pathname);
-  // cache is outdated now
-  dictionaries.clear();
   set_language(language);
 }
 
index 5d43063..207ce28 100644 (file)
@@ -104,13 +104,14 @@ private:
   SearchPath search_path;
   typedef std::map<std::string, std::string> Aliases;
   Aliases language_aliases;
+  std::string charset;
   std::string language;
   Dictionary* current_dict;
   Dictionary empty_dict;
 
 public:
   DictionaryManager();
-  
+
   /** Return the currently active dictionary, if none is set, an empty
       dictionary is returned. */
   Dictionary& get_dictionary()
@@ -122,6 +123,9 @@ public:
   /** Set a language based on a four? letter country code */
   void set_language(const std::string& langspec);
 
+  /** Set a charset that will be set on the returned dictionaries */
+  void set_charset(const std::string& charset);
+
   /** Define an alias for a language */
   void set_language_alias(const std::string& alias, const std::string& lang);
 
index 07974f6..6e098ea 100644 (file)
@@ -30,10 +30,15 @@ namespace SuperTux
  */
 enum HitResponse
 {
-  ABORT_MOVE,   // don't move the object
-  FORCE_MOVE,   // do the move ignoring the collision
-  CONTINUE      // move object out of collision and check for collisions again
-                // if this happens to often then the move will just be aborted
+  // note: keep the elements in this order
+
+  /// don't move the object
+  ABORT_MOVE = 0,
+  /// move object out of collision and check for collisions again
+  /// if this happens to often then the move will just be aborted    
+  CONTINUE,
+  /// do the move ignoring the collision
+  FORCE_MOVE
 };
 
 /**
index c73dc38..18c6067 100644 (file)
@@ -32,17 +32,18 @@ namespace SuperTux
 {
 
 Sprite::Sprite(SpriteData& newdata)
-  : data(newdata)
+  : data(newdata), frame(0), animation_loops(-1)
 {
   action = data.actions.begin()->second;
-  reset();
+  last_ticks = SDL_GetTicks();
 }
 
 Sprite::Sprite(const Sprite& other)
   : data(other.data), frame(other.frame),
-    animation_loops(other.animation_loops), last_tick(other.last_tick),
-    action(other.action), next_action(other.next_action)
+    animation_loops(other.animation_loops),
+    action(other.action)
 {
+  last_ticks = SDL_GetTicks();
 }
 
 Sprite::~Sprite()
@@ -50,34 +51,22 @@ Sprite::~Sprite()
 }
 
 void
-Sprite::set_action(std::string name)
+Sprite::set_action(std::string name, int loops)
 {
-  if(!next_action.empty() && animation_loops > 0) {
-    next_action = name;
+  if(action && action->name == name)
     return;
-  }
+
   SpriteData::Action* newaction = data.get_action(name);
-  if(!action)
+  if(!action) {
+#ifdef DEBUG
+    std::cerr << "Action '" << name << "' not found.\n";
+#endif
     return;
+  }
 
   action = newaction;
-}
-
-void
-Sprite::start_animation(int loops)
-{
-  reset();
   animation_loops = loops;
-}
-
-void
-Sprite::reset()
-{
   frame = 0;
-  last_tick = SDL_GetTicks();
-  animation_reversed = false;
-  animation_loops = -1;
-  next_action.clear();
 }
 
 bool
@@ -87,71 +76,24 @@ Sprite::check_animation()
 }
 
 void
-Sprite::reverse_animation(bool reverse)
-{
-  animation_reversed = reverse;
-
-  if(animation_reversed)
-    frame = get_frames()-1;
-  else
-    frame = 0;
-}
-
-void
 Sprite::update()
 {
   if(animation_loops == 0)
-  {
-    if(frame >= get_frames() || frame < 0)
-      frame = 0;
     return;
-  }
 
-  float frame_inc = (action->fps/1000.0) * (SDL_GetTicks() - last_tick);
-  last_tick = SDL_GetTicks();
+  Uint32 ticks = SDL_GetTicks();
+  float frame_inc = action->fps * float(ticks - last_ticks)/1000.0;
+  last_ticks = ticks;
 
-  if(animation_reversed)
-    frame -= frame_inc;
-  else
-    frame += frame_inc;
-
-  if(animation_reversed) {
-    if(frame < 0 || frame >= (float)get_frames()) {
-      // last case can happen when not used reverse_animation()
-      float excedent = frame - 0;
-      frame = get_frames() - 1;
-      if(animation_loops > 0)
-      {
-        animation_loops--;
-        if(animation_loops == 0 && !next_action.empty())
-        {
-          set_action(next_action);
-          start_animation(-1);
-        }
-      }
-
-      if(fabsf(excedent) < get_frames())
-        frame += excedent;
-    }
-  }
-  else
-  {
-    if(frame >= (float)get_frames())
-    {
-      float excedent = frame - get_frames();
-      frame = 0;
-      if(animation_loops > 0)
-      {
-        animation_loops--;
-        if(animation_loops == 0 && !next_action.empty())
-        {
-          set_action(next_action);
-          start_animation(-1);
-        }
-      }
-
-      if(excedent < get_frames())
-        frame += excedent;
+  frame += frame_inc;
+
+  float lastframe = frame;
+  frame = fmodf(frame+get_frames(), get_frames());
+  if(frame != lastframe) {
+    if(animation_loops > 0) {
+      animation_loops--;
+      if(animation_loops == 0)
+        frame = 0;
     }
   }
 }
index 655aba8..6d0ed7b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <string>
 #include <vector>
+#include <cassert>
 #include <map>
 
 #include "utils/lispreader.h"
@@ -47,20 +48,13 @@ namespace SuperTux
         Uint32 drawing_effect = NONE_EFFECT);
 
     /** Set action (or state) */
-    void set_action(std::string act);
+    void set_action(std::string act, int loops = -1);
 
-    /* Start an animation
-       -1 - for infinite
-       0  - stopped
-       1,2,3  - one, two, three times... */
-    void start_animation(int loops);
     /* Stop animation */
     void stop_animation()
-    { start_animation(0); }
+    { animation_loops = 0; }
     /** Check if animation is stopped or not */
     bool check_animation();
-    /** Reverse the animation */
-    void reverse_animation(bool reverse);
 
     float get_fps() const
     { return action->fps; }
@@ -85,24 +79,20 @@ namespace SuperTux
     { if(frame_ > get_frames()) frame = 0; else frame = frame_; }
     Surface* get_frame(unsigned int frame)
     {
-      if(frame < action->surfaces.size())
-        return action->surfaces[frame];
-      else
-        return action->surfaces[0];
+      assert(frame < action->surfaces.size());
+      return action->surfaces[frame];
     }    
+
   private:
     void update();
-    void reset();
 
     SpriteData& data;
 
     float frame;
     int animation_loops;
-    bool animation_reversed;
-    float last_tick;
+    Uint32 last_ticks;
 
     SpriteData::Action* action;
-    std::string next_action;
   };
 } //namespace SuperTux
 
index cfa3af2..b13c0d5 100644 (file)
@@ -194,6 +194,9 @@ BadGuy::set_state(State state)
       }
       flags |= FLAG_NO_COLLDET;
       break;
+    case STATE_FALLING:
+      flags |= FLAG_NO_COLLDET;
+      break;
     default:
       break;
   }
index d8ec812..1f62e61 100644 (file)
@@ -45,7 +45,7 @@ Dispenser::collision_squished(Player& player)
 }
 
 void
-Dispenser::active_action(float elapsed_time)
+Dispenser::active_action(float )
 {
    if (dispense_timer.check()) {
       launch_badguy();
index c75c990..0dcc549 100644 (file)
@@ -13,6 +13,8 @@
 #include "flower.h"
 #include "oneup.h"
 #include "star.h"
+#include "badguy/badguy.h"
+#include "coin.h"
 
 static const float BOUNCY_BRICK_MAX_OFFSET=8;
 static const float BOUNCY_BRICK_SPEED=90;
@@ -35,8 +37,6 @@ Block::~Block()
 HitResponse
 Block::collision(GameObject& other, const CollisionHit& hitdata)
 {
-  // TODO kill badguys when bumping them...
-  
   Player* player = dynamic_cast<Player*> (&other);
   if(player) {
     // collided from below?
@@ -45,6 +45,17 @@ Block::collision(GameObject& other, const CollisionHit& hitdata)
     }
   }
 
+  if(bouncing) {
+    BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
+    if(badguy) {
+      badguy->kill_fall();
+    }
+    Coin* coin = dynamic_cast<Coin*> (&other);
+    if(coin) {
+      coin->collect();
+    }
+  }
+
   return FORCE_MOVE;
 }
 
index 7bdded4..0799ef0 100644 (file)
@@ -5,7 +5,9 @@
 #include "video/drawing_context.h"
 #include "special/sprite_manager.h"
 #include "player.h"
+#include "sector.h"
 #include "scene.h"
+#include "gameobjs.h"
 
 Coin::Coin(const Vector& pos)
 {
@@ -30,6 +32,14 @@ Coin::draw(DrawingContext& context)
   sprite->draw(context, get_pos(), LAYER_TILES);
 }
 
+void
+Coin::collect()
+{
+  Sector::current()->player->get_status().incCoins();
+  Sector::current()->add_object(new BouncyCoin(get_pos()));
+  remove_me();
+}
+
 HitResponse
 Coin::collision(GameObject& other, const CollisionHit& )
 {
@@ -37,8 +47,7 @@ Coin::collision(GameObject& other, const CollisionHit& )
   if(player == 0)
     return ABORT_MOVE;
 
-  player->get_status().incCoins();
-  remove_me();
+  collect();
   return ABORT_MOVE;
 }
 
index a4157a4..051d1c0 100644 (file)
@@ -19,6 +19,8 @@ public:
   virtual void action(float elapsed_time);
   virtual void draw(DrawingContext& context);
 
+  void collect();
+
 private:
   Sprite* sprite;
 };
index e50bdab..cba8829 100644 (file)
@@ -91,29 +91,16 @@ void player_input_init(player_input_type* pplayer_input)
 }
 
 void
-TuxBodyParts::set_action(std::string action)
+TuxBodyParts::set_action(std::string action, int loops)
 {
   if(head != NULL)
-    head->set_action(action);
+    head->set_action(action, loops);
   if(body != NULL)
-    body->set_action(action);
+    body->set_action(action, loops);
   if(arms != NULL)
-    arms->set_action(action);
+    arms->set_action(action, loops);
   if(feet != NULL)
-    feet->set_action(action);
-}
-
-void
-TuxBodyParts::one_time_animation()
-{
-  if(head != NULL)
-    head->start_animation(1);
-  if(body != NULL)
-    body->start_animation(1);
-  if(arms != NULL)
-    arms->start_animation(1);
-  if(feet != NULL)
-    feet->start_animation(1);
+    feet->set_action(action, loops);
 }
 
 void
@@ -789,11 +776,9 @@ Player::draw(DrawingContext& context)
     if(size == BIG)
       {
       if(dir == LEFT)
-        tux_body->head->set_action("idle-left");
+        tux_body->head->set_action("idle-left", 1);
       else // dir == RIGHT
-        tux_body->head->set_action("idle-right");
-
-      tux_body->head->start_animation(1);
+        tux_body->head->set_action("idle-right", 1);
       }
 
     }
index bc47b13..ada9e96 100644 (file)
@@ -111,7 +111,7 @@ public:
     delete feet;
   }
 
-  void set_action(std::string action);
+  void set_action(std::string action, int loops = -1);
   void one_time_animation();
   void draw(DrawingContext& context, const Vector& pos, int layer,
                 Uint32 drawing_effect = NONE_EFFECT);
index c5b81a8..e5d76c9 100644 (file)
@@ -600,6 +600,8 @@ Sector::draw(DrawingContext& context)
   context.pop_transform();
 }
 
+static const float DELTA = .001;
+
 void
 Sector::collision_tilemap(MovingObject* object, int depth)
 {
@@ -701,7 +703,7 @@ Sector::collision_tilemap(MovingObject* object, int depth)
       return;
   }
   // move out of collision and try again
-  object->movement += hit.normal * (hit.depth + .05);
+  object->movement += hit.normal * (hit.depth + DELTA);
   collision_tilemap(object, depth+1);
 }
 
@@ -724,15 +726,15 @@ Sector::collision_object(MovingObject* object1, MovingObject* object2)
       if(response1 == ABORT_MOVE)
         object1->movement = Vector(0, 0);
       if(response2 == CONTINUE)
-        object2->movement += hit.normal * (hit.depth + .05);
+        object2->movement += hit.normal * (hit.depth + DELTA);
     } else if(response2 != CONTINUE) {
       if(response2 == ABORT_MOVE)
         object2->movement = Vector(0, 0);
       if(response1 == CONTINUE)
-        object1->movement += -hit.normal * (hit.depth + .05);
+        object1->movement += -hit.normal * (hit.depth + DELTA);
     } else {
-      object1->movement += -hit.normal * (hit.depth/2 + .05);
-      object2->movement += hit.normal * (hit.depth/2 + .05);
+      object1->movement += -hit.normal * (hit.depth/2 + DELTA);
+      object2->movement += hit.normal * (hit.depth/2 + DELTA);
     }
   }
 }
@@ -743,12 +745,16 @@ Sector::collision_handler()
   for(std::vector<GameObject*>::iterator i = gameobjects.begin();
       i != gameobjects.end(); ++i) {
     GameObject* gameobject = *i;
-    if(!gameobject->is_valid() 
-        || gameobject->get_flags() & GameObject::FLAG_NO_COLLDET)
+    if(!gameobject->is_valid())
       continue;
     MovingObject* movingobject = dynamic_cast<MovingObject*> (gameobject);
     if(!movingobject)
       continue;
+    if(movingobject->get_flags() & GameObject::FLAG_NO_COLLDET) {
+      movingobject->bbox.move(movingobject->movement);
+      movingobject->movement = Vector(0, 0);
+      continue;
+    }
 
     // collision with tilemap
     if(! (movingobject->movement == Vector(0, 0)))
index a832da9..1d576ae 100644 (file)
@@ -90,8 +90,7 @@ void
 Door::event(Player& , EventType type)
 {
   if(type == EVENT_ACTIVATE) {
-    sprite->set_action("open");
-    sprite->start_animation(1);
+    sprite->set_action("open", 1);
   }
 }