- added quick&dirty peeking back (not exactly perfect, but better then no peeking)
[supertux.git] / src / object / camera.cpp
index 0e66cbc..42dd1aa 100644 (file)
@@ -42,8 +42,9 @@
 class CameraConfig
 {
 public:
-  // 0 = No, 1 = Fix, 2 = Mario/Yoshi, 3 = Kirby, 4 = inverse rubber
+  // 0 = No, 1 = Fix, 2 = Mario/Yoshi, 3 = Kirby
   int ymode;
+  // as above, 4 = super metroid like
   int xmode;
   float kirby_rectsize_x;
   float kirby_rectsize_y;
@@ -61,11 +62,15 @@ public:
   float dirchange_time;
   // edge_x
   float edge_x;
+  // when too change from noscroll mode back to lookahead left/right mode
+  // set to <= 0 to disable noscroll mode
   float sensitive_x;
 
   float clamp_y;
   float clamp_x;
 
+  float dynamic_speed_sm;
+
   CameraConfig() {
     xmode = 1;
     ymode = 1;
@@ -81,6 +86,7 @@ public:
     sensitive_x = 1.f/4.f;
     dynamic_max_speed_x = 1.0;
     dirchange_time = 0.2f;
+    dynamic_speed_sm = 1.0f;
   }
 
   void load(const std::string& filename)
@@ -105,11 +111,13 @@ public:
     camconfig->get("kirby-rectsize-y", kirby_rectsize_y);
     camconfig->get("edge-x", edge_x);
     camconfig->get("sensitive-x", sensitive_x);
+    camconfig->get("dynamic-speed-sm", dynamic_speed_sm);
   }
 };
 
 Camera::Camera(Sector* newsector, std::string name)
-  : mode(NORMAL), sector(newsector), lookahead_mode(LOOKAHEAD_NONE)
+  : mode(NORMAL), sector(newsector), lookahead_mode(LOOKAHEAD_NONE),
+    lookahead_pos(0)
 {
   this->name = name;
   config = new CameraConfig();
@@ -300,11 +308,14 @@ Camera::update_scroll_normal(float elapsed_time)
     return;
 
   /****** Vertical Scrolling part ******/
+  int xmode = config.xmode;
   int ymode = config.ymode;
 
   if(player->is_dying() || sector->get_height() == 19*32) {
     ymode = 0;
   }
+  if(player->is_dying())
+    xmode = 0;
 
   if(ymode == 1) {
     translation.y = player_pos.y - SCREEN_HEIGHT * config.target_y;
@@ -353,10 +364,10 @@ Camera::update_scroll_normal(float elapsed_time)
 
   /****** Horizontal scrolling part *******/
 
-  if(config.xmode == 1) {
+  if(xmode == 1) {
     translation.x = player_pos.x - SCREEN_WIDTH * config.target_x;
   }
-  if(config.xmode == 2) {
+  if(xmode == 2) {
     // our camera is either in leftscrolling, rightscrolling or
     // nonscrollingmode.
     //
@@ -371,17 +382,30 @@ Camera::update_scroll_normal(float elapsed_time)
     else if (player->dir == ::LEFT) walkDirection = LOOKAHEAD_LEFT;
     else walkDirection = LOOKAHEAD_RIGHT;
 
-    float LEFTEND = SCREEN_WIDTH * config.sensitive_x;
-    float RIGHTEND = SCREEN_WIDTH * (1-config.sensitive_x);
+    float LEFTEND, RIGHTEND;
+    if(config.sensitive_x > 0) {
+      LEFTEND = SCREEN_WIDTH * config.sensitive_x;
+      RIGHTEND = SCREEN_WIDTH * (1-config.sensitive_x);
+    } else {
+      LEFTEND = SCREEN_WIDTH;
+      RIGHTEND = 0;
+    }
 
-    /* if we're undecided then look if we crossed the left or right "sensitive"
-     * area */
     if(lookahead_mode == LOOKAHEAD_NONE) {
+      /* if we're undecided then look if we crossed the left or right
+       * "sensitive" area */
       if(player_pos.x < translation.x + LEFTEND) {
         lookahead_mode = LOOKAHEAD_LEFT;
       } else if(player_pos.x > translation.x + RIGHTEND) {
         lookahead_mode = LOOKAHEAD_RIGHT;
       }
+      /* at the ends of a level it's obvious which way we will go */
+      if(player_pos.x < SCREEN_WIDTH*0.5) {
+        lookahead_mode = LOOKAHEAD_RIGHT;
+      } else if(player_pos.x >= sector->get_width() - SCREEN_WIDTH*0.5) {
+        lookahead_mode = LOOKAHEAD_LEFT;
+      }
+
       changetime = -1;
     } else if(lookahead_mode != walkDirection) {
       /* player changed direction while camera was scrolling...
@@ -437,17 +461,49 @@ Camera::update_scroll_normal(float elapsed_time)
     // apply scrolling
     translation.x -= speed_x * elapsed_time;
   }
-  if(config.xmode == 3) {
+  if(xmode == 3) {
     float halfsize = config.kirby_rectsize_x * 0.5f;
     translation.x = clamp(translation.x,
         player_pos.x - SCREEN_WIDTH * (0.5f + halfsize),
         player_pos.x - SCREEN_WIDTH * (0.5f - halfsize));
   }
-  if(config.xmode == 4) {
-    // TODO...
+  if(xmode == 4) {
+    float LEFTEND = SCREEN_WIDTH * config.edge_x;
+    float RIGHTEND = SCREEN_WIDTH * (1 - config.edge_x);
+
+    if (player_delta.x < -EPSILON) {
+      // walking left
+      lookahead_pos -= player_delta.x * config.dynamic_speed_sm;
+
+      if(lookahead_pos > RIGHTEND) {
+        lookahead_pos = RIGHTEND;
+      }
+    } else if (player_delta.x > EPSILON) {
+      // walking right
+      lookahead_pos -= player_delta.x * config.dynamic_speed_sm;
+      if(lookahead_pos < LEFTEND) {
+        lookahead_pos = LEFTEND;
+      }
+    }
+
+    if(player->peeking_direction() == ::LEFT) {
+      lookahead_pos += config.max_speed_x * elapsed_time * 3.0f;
+    } else if(player->peeking_direction() == ::RIGHT) {
+      lookahead_pos -= config.max_speed_x * elapsed_time * 3.0f;
+    }
+
+    // adjust for level ends
+    if (player_pos.x < LEFTEND) {
+      lookahead_pos = LEFTEND;
+    }
+    if (player_pos.x > sector->get_width() - LEFTEND) {
+      lookahead_pos = RIGHTEND;
+    }
+
+    translation.x = player_pos.x - lookahead_pos;
   }
 
-  if(config.xmode != 0 && config.clamp_x > 0) {
+  if(xmode != 0 && config.clamp_x > 0) {
     translation.x = clamp(translation.x,
         player_pos.x - SCREEN_WIDTH * (1-config.clamp_x),
         player_pos.x - SCREEN_WIDTH * config.clamp_x);