experimental Zeekling mod - swoops down when she spots the player
authorChristoph Sommer <mail@christoph-sommer.de>
Sat, 4 Mar 2006 00:08:09 +0000 (00:08 +0000)
committerChristoph Sommer <mail@christoph-sommer.de>
Sat, 4 Mar 2006 00:08:09 +0000 (00:08 +0000)
SVN-Revision: 3071

data/images/creatures/zeekling/diving.png [new file with mode: 0644]
data/images/sprites.strf
src/badguy/zeekling.cpp
src/badguy/zeekling.hpp

diff --git a/data/images/creatures/zeekling/diving.png b/data/images/creatures/zeekling/diving.png
new file mode 100644 (file)
index 0000000..082d2b8
Binary files /dev/null and b/data/images/creatures/zeekling/diving.png differ
index fefa3ed..f81049e 100644 (file)
          (name "squished-right")
          (x-offset 2)
          (y-offset -19)
-         (mirror-action "squished-left")))
+         (mirror-action "squished-left"))
+       (action
+         (name "diving-left")
+         (x-offset 2)
+         (y-offset 4)
+         (images "creatures/zeekling/diving.png"))
+       (action
+         (name "diving-right")
+         (x-offset 2)
+         (y-offset 4)
+         (mirror-action "left")))
 
 ; Angry Stone
  (sprite (name "angrystone")
index 0b2758d..65ae3e9 100644 (file)
@@ -1,7 +1,8 @@
 //  $Id$
 // 
-//  SuperTux
+//  Zeekling - flyer that swoops down when she spots the player
 //  Copyright (C) 2005 Matthias Braun <matze@braunis.de>
+//  Copyright (C) 2006 Christoph Sommer <supertux@2006.expires.deltadevelopment.de>
 //
 //  This program is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU General Public License
@@ -23,8 +24,6 @@
 
 #include "zeekling.hpp"
 
-
-//TODO: Make the Zeekling behave more interesting
 Zeekling::Zeekling(const lisp::Lisp& reader)
 {
   reader.get("x", start_position.x);
@@ -32,6 +31,7 @@ Zeekling::Zeekling(const lisp::Lisp& reader)
   bbox.set_size(31.8, 31.8);
   sprite = sprite_manager->create("zeekling");
   set_direction = false;
+  state = FLYING;
 }
 
 Zeekling::Zeekling(float pos_x, float pos_y, Direction d)
@@ -42,6 +42,7 @@ Zeekling::Zeekling(float pos_x, float pos_y, Direction d)
   sprite = sprite_manager->create("zeekling");
   set_direction = true;
   initial_direction = d;
+  state = FLYING;
 }
 
 void
@@ -74,18 +75,121 @@ Zeekling::collision_squished(Player& player)
   return true;
 }
 
-HitResponse
-Zeekling::collision_solid(GameObject& , const CollisionHit& hit)
-{
-  if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
+void 
+Zeekling::onBumpHorizontal() {
+  if (state == FLYING) {
+    dir = (dir == LEFT ? RIGHT : LEFT);
+    sprite->set_action(dir == LEFT ? "left" : "right");
+    physic.set_velocity_x(dir == LEFT ? -speed : speed);
+  } else
+  if (state == DIVING) {
+    dir = (dir == LEFT ? RIGHT : LEFT);
+    state = FLYING;
+    sprite->set_action(dir == LEFT ? "left" : "right");
+    physic.set_velocity_x(dir == LEFT ? -speed : speed);
     physic.set_velocity_y(0);
-  } else { // hit right or left
+  } else
+  if (state == CLIMBING) {
     dir = (dir == LEFT ? RIGHT : LEFT);
     sprite->set_action(dir == LEFT ? "left" : "right");
     physic.set_velocity_x(dir == LEFT ? -speed : speed);
   }
+}
+
+void 
+Zeekling::onBumpVertical() {
+  if (state == FLYING) {
+    physic.set_velocity_y(0);
+  } else
+  if (state == DIVING) {
+    state = CLIMBING;
+    physic.set_velocity_y(speed);
+    sprite->set_action(dir == LEFT ? "left" : "right");
+  } else
+  if (state == CLIMBING) {
+    state = FLYING;
+    physic.set_velocity_y(0);
+  }
+}
+
+HitResponse
+Zeekling::collision_solid(GameObject& , const CollisionHit& hit)
+{
+  if(fabsf(hit.normal.y) > .5) {
+    onBumpVertical(); 
+  } else {
+    onBumpHorizontal();
+  }
 
   return CONTINUE;
 }
 
+/**
+ * linear prediction of player and badguy positions to decide if we should enter the DIVING state
+ */
+bool 
+Zeekling::should_we_dive() {
+  const MovingObject* player = Sector::current()->player;
+  const MovingObject* badguy = this;
+
+  const Vector playerPos = player->get_pos();
+  const Vector playerMov = player->get_movement();
+
+  const Vector badguyPos = badguy->get_pos();
+  const Vector badguyMov = badguy->get_movement();
+
+  // new vertical speed to test with
+  float vy = -2*fabsf(badguyMov.x);
+
+  // do not dive if we are not above the player
+  float height = playerPos.y - badguyPos.y;
+  if (height <= 0) return false;
+
+  // do not dive if we would not descend faster than the player
+  float relSpeed = -vy + playerMov.y;
+  if (relSpeed <= 0) return false;
+
+  // guess number of frames to descend to same height as player
+  float estFrames = height / relSpeed;
+  
+  // guess where the player would be at this time
+  float estPx = (playerPos.x + (estFrames * playerMov.x));
+
+  // guess where we would be at this time
+  float estBx = (badguyPos.x + (estFrames * badguyMov.x));
+
+  // near misses are OK, too
+  if (fabsf(estPx - estBx) < 32) return true;
+
+  return false;
+}
+
+void 
+Zeekling::active_update(float elapsed_time) {
+  BadGuy::active_update(elapsed_time);
+
+  if (state == FLYING) {
+    if (should_we_dive()) {
+      state = DIVING;
+      physic.set_velocity_y(-2*fabsf(physic.get_velocity_x()));
+      sprite->set_action(dir == LEFT ? "diving-left" : "diving-right");
+    }
+    return;
+  }
+
+  if (state == DIVING) {
+    return;
+  }
+
+  if (state == CLIMBING) {
+    // stop climbing when we're back at initial height
+    if (get_pos().y <= start_position.y) {
+      state = FLYING;
+      physic.set_velocity_y(0);
+    }
+    return;
+  }
+
+}
+
 IMPLEMENT_FACTORY(Zeekling, "zeekling")
index 7dc18af..ab45abc 100644 (file)
@@ -1,7 +1,8 @@
 //  $Id$
 // 
-//  SuperTux
+//  Zeekling - flyer that swoops down when she spots the player
 //  Copyright (C) 2005 Matthias Braun <matze@braunis.de>
+//  Copyright (C) 2006 Christoph Sommer <supertux@2006.expires.deltadevelopment.de>
 //
 //  This program is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU General Public License
@@ -32,12 +33,28 @@ public:
   void activate();
   void write(lisp::Writer& writer);
   HitResponse collision_solid(GameObject& other, const CollisionHit& hit);
+  void active_update(float elapsed_time);
 
 protected:
   bool collision_squished(Player& player);
   bool set_direction;
   Direction initial_direction;
   float speed;
+
+  Timer diveRecoverTimer;
+
+  enum ZeeklingState {
+    FLYING,
+    DIVING,
+    CLIMBING
+  };
+  ZeeklingState state;
+
+private:
+  bool should_we_dive();
+  void onBumpHorizontal();
+  void onBumpVertical();
+
 };
 
 #endif