Browse Source

Working animated starfield with panel.

Steve Thielemann 3 years ago
parent
commit
62bd4b6a0e
3 changed files with 114 additions and 236 deletions
  1. 32 19
      main.cpp
  2. 75 214
      starfield.cpp
  3. 7 3
      starfield.h

+ 32 - 19
main.cpp

@@ -380,30 +380,18 @@ int main(int argc, char *argv[]) {
 
   Starfield mainfield(door, rng);
 
-  cls_display_starfield = [&mainfield]() -> void {
-    mainfield.display();
-    // display_starfield(door, rng);
-  };
+  cls_display_starfield = [&mainfield]() -> void { mainfield.display(); };
 
   /*
-    // FIX ANIMATION.  Yuck!
-
-    mainfield.display();
-    int delay;
-    for (delay = 0; delay < 80; ++delay) {
-      door.sleep_ms_key(100);
-      mainfield.animate();
+    AnimatedStarfield amazing(door, rng);
+    amazing.display();
+    int res = -1;
+    while (res == -1) {
+      res = door.sleep_ms_key(250);
+      amazing.animate();
     }
   */
 
-  AnimatedStarfield amazing(door, rng);
-  amazing.display();
-  int res = -1;
-  while (res == -1) {
-    res = door.sleep_ms_key(250);
-    amazing.animate();
-  }
-
   DBData spacedb;
   spacedb.setUser(door.username);
 
@@ -553,6 +541,31 @@ int main(int argc, char *argv[]) {
   // center the help box
   help.set((mx - 60) / 2, (my - 15) / 2);
 
+  /*
+  // animated starfield with about panel
+    AnimatedStarfield amazing(door, rng);
+
+    checkVisibleFunction about_visible = [&about](int x, int y) -> bool {
+      int px, py;
+      about.get(px, py);
+      int pw = about.getWidth();
+      int ph = about.getHeight();
+      if ((x >= px) and (x <= (px + pw + 1)) and (y >= py) and (y <= py + ph))
+        return false;
+      return true;
+    };
+    amazing.setVisible(about_visible);
+    amazing.regenerate();
+    amazing.display();
+    door << about << door::reset;
+
+    int res = -1;
+    while (res == -1) {
+      res = door.sleep_ms_key(250);
+      amazing.animate();
+    }
+  */
+
   PlayCards pc(door, spacedb, rng);
   Starfield menu_stars(door, rng);
 

+ 75 - 214
starfield.cpp

@@ -41,87 +41,6 @@ void Starfield::regenerate(void) {
   }
 }
 
-#ifdef NOMORE
-
-void Starfield::animate(void) {
-  int rx = uni_x(rng);
-  int ry = uni_y(rng);
-  int mx = door.width;
-  int my = door.height;
-  int cx = mx / 2;
-  int cy = my / 2;
-
-  std::set<star_pos> original = sky;
-  sky.clear();
-
-  for (auto &spos : original) {
-    star_pos orig = spos;
-    star_pos newpos = orig;
-
-    int dx = mx - abs(orig.x - cx);
-    int dy = my - abs(orig.y - cy);
-    if (dx > rx) {
-      // something x
-      if (newpos.x > cx)
-        ++newpos.x;
-      else
-        --newpos.x;
-    }
-    if (dy > ry) {
-      // something y
-      if (newpos.y > cy)
-        ++newpos.y;
-      else
-        --newpos.y;
-    }
-
-    if ((newpos.x == 0) or (newpos.x >= mx) or (newpos.y == 0) or
-        (newpos.y >= my)) {
-      newpos = make_pos();
-      newpos.color = orig.color;
-      newpos.symbol = orig.symbol;
-    }
-
-    if (sky.find(newpos) == sky.end()) {
-      door << door::Goto(orig.x, orig.y) << " ";
-      sky.insert(newpos);
-      door << door::Goto(newpos.x, newpos.y);
-      if (newpos.color)
-        door << dark;
-      else
-        door << white;
-
-      if (newpos.symbol)
-        door << stars[0];
-      else
-        door << stars[1];
-
-    } else {
-      // rats!
-      if (sky.find(orig) == sky.end()) {
-        sky.insert(orig);
-      } else {
-        door << door::Goto(orig.x, orig.y) << " ";
-        newpos = make_pos();
-        newpos.color = orig.color;
-        newpos.symbol = orig.symbol;
-        sky.insert(newpos);
-        door << door::Goto(newpos.x, newpos.y);
-        if (newpos.color)
-          door << dark;
-        else
-          door << white;
-
-        if (newpos.symbol)
-          door << stars[0];
-        else
-          door << stars[1];
-      }
-    }
-  }
-}
-#endif
-
 void Starfield::display(void) {
   door << door::reset << door::cls;
 
@@ -180,100 +99,6 @@ void Starfield::display(void) {
   }
 }
 
-#ifdef NOMORE
-void display___starfield(door::Door &door, std::mt19937 &rng) {
-  door << door::reset << door::cls;
-
-  int mx = door.width;
-  int my = door.height;
-
-  // display Starfield
-  const char *stars[2];
-
-  stars[0] = ".";
-  if (door::unicode) {
-    stars[1] = "\u2219"; // "\u00b7";
-
-  } else {
-    stars[1] = "\xf9"; // "\xfa";
-  };
-
-  {
-    // Make uniform random distribution between 1 and MAX screen size X/Y
-    std::uniform_int_distribution<int> uni_x(1, mx);
-    std::uniform_int_distribution<int> uni_y(1, my);
-
-    door::ANSIColor white(door::COLOR::WHITE);
-    door::ANSIColor dark(door::COLOR::BLACK, door::ATTR::BRIGHT);
-
-    // 10 is too many, 100 is too few. 40 looks ok.
-    int MAX_STARS = ((mx * my) / 40);
-    // door.log() << "Generating starmap using " << mx << "," << my << " : "
-    //           << MAX_STARS << " stars." << std::endl;
-
-    std::set<star_pos> sky;
-
-    for (int i = 0; i < MAX_STARS; i++) {
-      star_pos pos;
-      bool valid;
-      do {
-        pos.x = uni_x(rng);
-        pos.y = uni_y(rng);
-        auto ret = sky.insert(pos);
-        // was insert a success?  (not a duplicate)
-        valid = ret.second;
-      } while (!valid);
-    }
-
-    int i = 0;
-    star_pos last_pos;
-
-    for (auto &pos : sky) {
-      bool use_goto = true;
-
-      if (i != 0) {
-        // check last_pos to current position
-        if (pos.y == last_pos.y) {
-          // Ok, same row -- try some optimizations
-          int dx = pos.x - last_pos.x;
-          if (dx == 0) {
-            use_goto = false;
-          } else {
-            if (dx < 5) {
-              door << std::string(dx, ' ');
-              use_goto = false;
-            } else {
-              // Use ANSI Cursor Forward
-              door << "\x1b[" << dx << "C";
-              use_goto = false;
-            }
-          }
-        }
-      }
-
-      if (use_goto) {
-        door::Goto star_at(pos.x, pos.y);
-        door << star_at;
-      }
-
-      if (i % 5 < 2)
-        door << dark;
-      else
-        door << white;
-
-      if (i % 2 == 0)
-        door << stars[0];
-      else
-        door << stars[1];
-
-      ++i;
-      last_pos = pos;
-      last_pos.x++; // star output moves us by one.
-    }
-  }
-}
-#endif
-
 AnimatedStarfield::AnimatedStarfield(door::Door &Door, std::mt19937 &Rng)
     : door{Door}, rng{Rng}, uni_x{1, Door.width}, uni_y{1, Door.height},
       white{door::COLOR::WHITE}, dark{door::COLOR::BLACK, door::ATTR::BRIGHT} {
@@ -288,17 +113,45 @@ AnimatedStarfield::AnimatedStarfield(door::Door &Door, std::mt19937 &Rng)
   regenerate();
 }
 
-moving_star AnimatedStarfield::make_pos(void) {
+/**
+ * @brief Make a moving_star
+ *
+ * This makes a new x,y point.
+ *
+ * If "centered", we create a point nearer to the center of the screen.
+ *
+ * Also, if centered, we don't allow y == cy.  FIXES BUG: syncterm 80x25.
+ *
+ * moving_star.visible is set by the visibleFunction.
+ * moving_star.xpos, ypos is initialized from x,y.
+ * moving_star.movex, movey is initialized from the rise/run from center.
+ * @param centered
+ * @return moving_star
+ */
+moving_star AnimatedStarfield::make_pos(bool centered) {
   moving_star pos;
-  pos.x = uni_x(rng);
-  pos.y = uni_y(rng);
-  pos.xpos = pos.x;
-  pos.ypos = pos.y;
-  pos.movex = pos.xpos - cx;
-  pos.movey = pos.ypos - cy;
-  double bigd = max(abs(pos.movex), abs(pos.movey));
-  pos.movex /= bigd;
-  pos.movey /= bigd;
+  do {
+    pos.x = uni_x(rng);
+    pos.y = uni_y(rng);
+    pos.visible = true;
+    if (centered) {
+      pos.x /= 4;
+      pos.x += cx - (cx / 4);
+      pos.y /= 4;
+      pos.y += cy - (cy / 4);
+    }
+    pos.xpos = pos.x;
+    pos.ypos = pos.y;
+    pos.movex = pos.xpos - cx;
+    pos.movey = pos.ypos - cy;
+    double bigd = max(abs(pos.movex), abs(pos.movey));
+    pos.movex /= bigd;
+    pos.movey /= bigd;
+
+    if (visible) {
+      pos.visible = visible(pos.x, pos.y);
+    }
+  } while (centered and (pos.y == cy));
 
   /*
     if (get_logger)
@@ -320,14 +173,8 @@ void AnimatedStarfield::regenerate(void) {
 
   for (int i = 0; i < MAX_STARS; i++) {
     moving_star pos = make_pos();
-    // store symbol and color in star_pos.
-    // If we do any animation, we won't be able to rely on the star_pos keeping
-    // the same position in the set.
     pos.symbol = i % 2;
     pos.color = i % 5 < 2;
-    pos.xpos = pos.x;
-    pos.ypos = pos.y;
-    // calculate movex, movey here and now!
     sky.push_back(pos);
   }
 }
@@ -343,18 +190,20 @@ void AnimatedStarfield::display(void) {
   };
 
   for (auto &pos : sky) {
-    door::Goto star_at(pos.x, pos.y);
-    door << star_at;
+    if (pos.visible) {
+      door::Goto star_at(pos.x, pos.y);
+      door << star_at;
 
-    if (pos.color)
-      door << dark;
-    else
-      door << white;
+      if (pos.color)
+        door << dark;
+      else
+        door << white;
 
-    if (pos.symbol)
-      door << stars[0];
-    else
-      door << stars[1];
+      if (pos.symbol)
+        door << stars[0];
+      else
+        door << stars[1];
+    }
   }
 }
 
@@ -364,7 +213,7 @@ void AnimatedStarfield::animate(void) {
     // just start with basic movement
     // double speed = abs((cx / 2) - distance(star.movex, star.movey));
     double speed = max_d / distance(star.movex, star.movey);
-    star.xpos += star.movex / (speed * 4);
+    star.xpos += star.movex / (speed * (mx / my));
     star.ypos += star.movey / speed;
 
     int nx = int(star.xpos + 0.5);
@@ -376,7 +225,7 @@ void AnimatedStarfield::animate(void) {
     while ((star.xpos < 1) or (star.xpos >= mx - 1) or (star.ypos < 1) or
            (star.ypos >= my - 1)) {
       // off the screen!  Whoops!
-      moving_star new_pos = make_pos();
+      moving_star new_pos = make_pos(true);
       nx = new_pos.x;
       ny = new_pos.y;
       star.xpos = new_pos.x;
@@ -390,23 +239,35 @@ void AnimatedStarfield::animate(void) {
     // if ((star.x != int(star.xpos)) or (star.y == int(star.ypos))) {
     if ((star.x != nx) or (star.y != ny)) {
       // star has moved, update time
-      door << door::Goto(star.x, star.y) << " ";
+      if (star.visible) {
+        door << door::Goto(star.x, star.y) << " ";
+      };
       star.x = nx; // int(star.xpos);
       star.y = ny; // int(star.ypos);
-      door << door::Goto(star.x, star.y);
-      if (star.color)
-        door << dark;
-      else
-        door << white;
 
-      if (star.symbol)
-        door << stars[0];
-      else
-        door << stars[1];
+      if (visible) {
+        star.visible = visible(star.x, star.y);
+      }
+
+      // still visible?
+      if (star.visible) {
+        door << door::Goto(star.x, star.y);
+        if (star.color)
+          door << dark;
+        else
+          door << white;
+
+        if (star.symbol)
+          door << stars[0];
+        else
+          door << stars[1];
+      }
     }
   }
 }
 
 double AnimatedStarfield::distance(double x, double y) {
   return sqrt(((cx - x) * (cx - x)) + ((cy - y) * (cy - y)));
-}
+}
+
+void AnimatedStarfield::setVisible(checkVisibleFunction cvf) { visible = cvf; }

+ 7 - 3
starfield.h

@@ -56,20 +56,22 @@ struct moving_star {
   int y;
   int symbol;
   int color;
-
+  bool visible;
   double xpos;
   double ypos;
   double movex;
   double movey;
 };
 
+typedef std::function<bool(int x, int y)> checkVisibleFunction;
+
 class AnimatedStarfield {
   door::Door &door;
   std::mt19937 &rng;
   std::vector<moving_star> sky;
   std::uniform_int_distribution<int> uni_x;
   std::uniform_int_distribution<int> uni_y;
-  moving_star make_pos(void);
+  moving_star make_pos(bool centered = false);
 
   int mx;
   int my;
@@ -81,12 +83,14 @@ class AnimatedStarfield {
   door::ANSIColor dark;
   const char *stars[2];
   double distance(double x, double y);
+  checkVisibleFunction visible;
 
 public:
   AnimatedStarfield(door::Door &door, std::mt19937 &Rng);
   void regenerate(void);
   void display(void);
   void animate(void);
+  void setVisible(checkVisibleFunction cvf);
 };
 
-#endif
+#endif