Browse Source

Updated starfield, control when used.

This allows for in-play to refresh, and not change the stars.
The config menu keeps the same starfield.
Main menu, help, and about keep the same starfield.
I've created an animated starfield.
Steve Thielemann 3 years ago
parent
commit
adc79f6d57
8 changed files with 350 additions and 38 deletions
  1. 3 0
      deck.cpp
  2. 32 8
      main.cpp
  3. 6 2
      play.cpp
  4. 2 0
      play.h
  5. 2 1
      scores.cpp
  6. 3 1
      scores.h
  7. 248 24
      starfield.cpp
  8. 54 2
      starfield.h

+ 3 - 0
deck.cpp

@@ -3,6 +3,7 @@
 #include "space.h"
 #include "utils.h"
 #include "version.h"
+
 #include <algorithm>
 #include <iomanip> // setw
 #include <map>
@@ -1203,6 +1204,7 @@ door::Panel make_help(void) {
   return help;
 }
 
+#ifdef NOMORE
 /**
  * @brief Display starfield
  *
@@ -1333,6 +1335,7 @@ void display_starfield(door::Door &door, std::mt19937 &rng) {
     }
   }
 }
+#endif
 
 void display_space_ace(door::Door &door) {
   int mx = door.width;

+ 32 - 8
main.cpp

@@ -12,9 +12,9 @@
 #include "deck.h"
 #include "play.h"
 #include "scores.h"
+#include "starfield.h"
 #include "utils.h"
 #include "version.h"
-#include "starfield.h"
 #include <algorithm> // transform
 
 // configuration here -- access via extern
@@ -378,13 +378,32 @@ int main(int argc, char *argv[]) {
   std::random_device rd;
   std::mt19937 rng(rd());
 
-  starfield mainfield(door, rng);
+  Starfield mainfield(door, rng);
 
   cls_display_starfield = [&mainfield]() -> void {
     mainfield.display();
-    //display_starfield(door, rng);
+    // display_starfield(door, rng);
   };
 
+  /*
+    // 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();
+  }
+
   DBData spacedb;
   spacedb.setUser(door.username);
 
@@ -535,11 +554,13 @@ int main(int argc, char *argv[]) {
   help.set((mx - 60) / 2, (my - 15) / 2);
 
   PlayCards pc(door, spacedb, rng);
+  Starfield menu_stars(door, rng);
 
   int r = 0;
   while ((r >= 0) and (r != 6)) {
     // starfield + menu ?
-    display_starfield(door, rng);
+    // display_starfield(door, rng);
+    menu_stars.display();
     r = m.choose(door);
     // need to reset the colors.  (whoops!)
     door << door::reset << door::cls; // door::nl;
@@ -557,7 +578,7 @@ int main(int argc, char *argv[]) {
 
       // door << door::cls;
       {
-        Scores score(door, spacedb);
+        Scores score(door, spacedb, menu_stars);
 
         score.display_scores(door);
       }
@@ -570,13 +591,15 @@ int main(int argc, char *argv[]) {
       break;
 
     case 4: // help
-      display_starfield(door, rng);
+      // display_starfield(door, rng);
+      menu_stars.display();
       door << help << door::nl;
       r = press_a_key();
       break;
 
     case 5: // about
-      display_starfield(door, rng);
+      // display_starfield(door, rng);
+      menu_stars.display();
       door << about << door::nl;
       r = press_a_key();
       break;
@@ -604,7 +627,8 @@ int main(int argc, char *argv[]) {
   door << door::nl;
 
   // door << door::reset << door::cls;
-  display_starfield(door, rng);
+  // display_starfield(door, rng);
+  mainfield.display();
   door << m << door::reset << door::nl;
 
   // Normal DOOR exit goes here...

+ 6 - 2
play.cpp

@@ -17,7 +17,7 @@
 #define CHEATER "_CHEAT_YOUR_ASS_OFF"
 
 PlayCards::PlayCards(door::Door &d, DBData &dbd, std::mt19937 &r)
-    : door{d}, db{dbd}, rng{r} {
+    : door{d}, db{dbd}, rng{r}, stars{d, r} {
   init_values();
 
   play_day = std::chrono::system_clock::now();
@@ -167,10 +167,13 @@ CALENDAR_UPDATE:
   calendar->update();
   //}
 
+  stars.display();
+  /*
   if (cls_display_starfield)
     cls_display_starfield();
   else
     door << door::reset << door::cls;
+  */
 
   door << *calendar;
 
@@ -760,7 +763,8 @@ next_hand:
 void PlayCards::redraw(bool dealing) {
   shared_panel c;
 
-  display_starfield(door, rng);
+  stars.display();
+  // display_starfield(door, rng);
   // door << door::reset << door::cls;
   door << *spaceAceTriPeaks;
 

+ 2 - 0
play.h

@@ -4,6 +4,7 @@
 #include "db.h"
 #include "deck.h"
 #include "door.h"
+#include "starfield.h"
 
 #include <chrono>
 #include <random>
@@ -14,6 +15,7 @@ private:
   DBData &db;
   std::mt19937 &rng;
   std::vector<int> seeds;
+  Starfield stars;
 
   int month_last_day;
   /**

+ 2 - 1
scores.cpp

@@ -194,7 +194,8 @@ std::unique_ptr<door::Panel> Scores::make_top_this_month_panel() {
   return p;
 }
 
-Scores::Scores(door::Door &d, DBData &dbd) : door{d}, db{dbd} {
+Scores::Scores(door::Door &d, DBData &dbd, Starfield &sf)
+    : door{d}, db{dbd}, stars{sf} {
   top_scores = make_top_scores_panel();
   top_this_month = make_top_this_month_panel();
 }

+ 3 - 1
scores.h

@@ -1,10 +1,12 @@
 #include "db.h"
 #include "door.h"
+#include "starfield.h"
 
 class Scores {
 private:
   door::Door &door;
   DBData &db;
+  Starfield &stars;
 
   std::unique_ptr<door::Panel> top_scores;
   std::unique_ptr<door::Panel> top_this_month;
@@ -13,7 +15,7 @@ private:
   std::unique_ptr<door::Panel> make_top_this_month_panel();
 
 public:
-  Scores(door::Door &d, DBData &dbd);
+  Scores(door::Door &d, DBData &dbd, Starfield &sf);
 
   void display_scores(door::Door &door);
 };

+ 248 - 24
starfield.cpp

@@ -1,17 +1,29 @@
 #include "starfield.h"
+#include "utils.h"
 
-starfield::starfield(door::Door &Door, std::mt19937 &Rng)
-    : door{Door}, rng{Rng} {
+Starfield::Starfield(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} {
+  // std::uniform_int_distribution<int> uni_x(1, mx);
+  // std::uniform_int_distribution<int> uni_y(1, my);
   regenerate();
 }
 
-void starfield::regenerate(void) {
+star_pos Starfield::make_pos(void) {
+  star_pos pos;
+  do {
+    pos.x = uni_x(rng);
+    pos.y = uni_y(rng);
+  } while (sky.find(pos) != sky.end());
+  return pos;
+}
+
+void Starfield::regenerate(void) {
   int mx = door.width;
   int my = door.height;
 
   // 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);
+  sky.clear();
 
   // 10 is too many, 100 is too few. 40 looks ok.
   int MAX_STARS = ((mx * my) / 40);
@@ -19,36 +31,109 @@ void starfield::regenerate(void) {
   //           << MAX_STARS << " stars." << std::endl;
 
   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);
+    star_pos 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;
+    sky.insert(pos);
   }
 }
 
-void starfield::display(void) {
-  door << door::reset << door::cls;
+#ifdef NOMORE
 
-  door::ANSIColor white(door::COLOR::WHITE);
-  door::ANSIColor dark(door::COLOR::BLACK, door::ATTR::BRIGHT);
+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;
+    }
 
-  // display starfield
-  const char *stars[2];
+    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;
 
   stars[0] = ".";
   if (door::unicode) {
     stars[1] = "\u2219"; // "\u00b7";
-
   } else {
     stars[1] = "\xf9"; // "\xfa";
   };
 
   int i = 0;
+  // lose int i, and set last_pos to -1, -1.
   star_pos last_pos;
 
   for (auto &pos : sky) {
@@ -79,12 +164,12 @@ void starfield::display(void) {
       door << star_at;
     }
 
-    if (i % 5 < 2)
+    if (pos.color)
       door << dark;
     else
       door << white;
 
-    if (i % 2 == 0)
+    if (pos.symbol)
       door << stars[0];
     else
       door << stars[1];
@@ -95,13 +180,14 @@ 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
+  // display Starfield
   const char *stars[2];
 
   stars[0] = ".";
@@ -186,3 +272,141 @@ void display___starfield(door::Door &door, std::mt19937 &rng) {
     }
   }
 }
+#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} {
+  mx = door.width;
+  my = door.height;
+  cx = mx / 2.0;
+  cy = my / 2.0;
+  max_d = distance(0, 0);
+
+  // std::uniform_int_distribution<int> uni_x(1, mx);
+  // std::uniform_int_distribution<int> uni_y(1, my);
+  regenerate();
+}
+
+moving_star AnimatedStarfield::make_pos(void) {
+  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;
+
+  /*
+    if (get_logger)
+      get_logger() << pos.x << "," << pos.y << " " << pos.movex << "/"
+                   << pos.movey << std::endl;
+  */
+
+  return pos;
+}
+
+void AnimatedStarfield::regenerate(void) {
+  // Make uniform random distribution between 1 and MAX screen size X/Y
+  sky.clear();
+
+  // 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;
+
+  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);
+  }
+}
+
+void AnimatedStarfield::display(void) {
+  door << door::reset << door::cls;
+
+  stars[0] = ".";
+  if (door::unicode) {
+    stars[1] = "\u2219"; // "\u00b7";
+  } else {
+    stars[1] = "\xf9"; // "\xfa";
+  };
+
+  for (auto &pos : sky) {
+    door::Goto star_at(pos.x, pos.y);
+    door << star_at;
+
+    if (pos.color)
+      door << dark;
+    else
+      door << white;
+
+    if (pos.symbol)
+      door << stars[0];
+    else
+      door << stars[1];
+  }
+}
+
+void AnimatedStarfield::animate(void) {
+
+  for (auto &star : sky) {
+    // 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.ypos += star.movey / speed;
+
+    int nx = int(star.xpos + 0.5);
+    int ny = int(star.ypos + 0.5);
+
+    // watch the bottom of the screen!  It'll scroll!
+    // watch new position we're given!
+
+    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();
+      nx = new_pos.x;
+      ny = new_pos.y;
+      star.xpos = new_pos.x;
+      star.ypos = new_pos.y;
+      star.movex = new_pos.movex;
+      star.movey = new_pos.movey;
+      // new position updated -- next section will erase and display in new
+      // position
+    }
+
+    // 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) << " ";
+      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];
+    }
+  }
+}
+
+double AnimatedStarfield::distance(double x, double y) {
+  return sqrt(((cx - x) * (cx - x)) + ((cy - y) * (cy - y)));
+}

+ 54 - 2
starfield.h

@@ -1,3 +1,6 @@
+#ifndef STARFIELD_H
+#define STARFIELD_H
+
 #include "door.h"
 #include <random>
 #include <set>
@@ -5,6 +8,8 @@
 struct star_pos {
   int x;
   int y;
+  int symbol;
+  int color;
 
   /**
    * @brief Provide less than operator.
@@ -28,13 +33,60 @@ struct star_pos {
   }
 };
 
-class starfield {
+class Starfield {
   door::Door &door;
   std::mt19937 &rng;
   std::set<star_pos> sky;
+  std::uniform_int_distribution<int> uni_x;
+  std::uniform_int_distribution<int> uni_y;
+  star_pos make_pos(void);
+
+  door::ANSIColor white; //(door::COLOR::WHITE);
+  door::ANSIColor dark;  //(door::COLOR::BLACK, door::ATTR::BRIGHT);
+  const char *stars[2];
+
+public:
+  Starfield(door::Door &Door, std::mt19937 &Rng);
+  void regenerate(void);
+  void display(void);
+};
+
+struct moving_star {
+  int x;
+  int y;
+  int symbol;
+  int color;
+
+  double xpos;
+  double ypos;
+  double movex;
+  double movey;
+};
+
+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);
+
+  int mx;
+  int my;
+  double cx;
+  double cy;
+  double max_d;
+
+  door::ANSIColor white;
+  door::ANSIColor dark;
+  const char *stars[2];
+  double distance(double x, double y);
 
 public:
-  starfield(door::Door &Door, std::mt19937 &Rng);
+  AnimatedStarfield(door::Door &door, std::mt19937 &Rng);
   void regenerate(void);
   void display(void);
+  void animate(void);
 };
+
+#endif