pong: configurable speed
Stefan Schuermans

Stefan Schuermans commited on 2019-06-16 11:28:22
Showing 5 changed files, with 84 additions and 17 deletions.

... ...
@@ -16,6 +16,7 @@
16 16
 #include "Mgrs.h"
17 17
 #include "Module.h"
18 18
 #include "OutStreamFile.h"
19
+#include "UIntFile.h"
19 20
 
20 21
 namespace Blinker {
21 22
 
... ...
@@ -277,7 +278,7 @@ bool Game::colorUpdate(ColorFile &colorFile, ColorData &data) const
277 278
 /// convert color to raw color data
278 279
 void Game::color2data(ColorFile const &colorFile, ColorData &data) const
279 280
 {
280
-  if (! m_fileFormat.m_valid) {
281
+  if (! m_fileFormat.m_valid || ! colorFile.m_valid) {
281 282
     data.clear();
282 283
   } else {
283 284
     unsigned int channels = m_fileFormat.m_obj.m_channels;
... ...
@@ -306,6 +307,36 @@ void Game::color2data(ColorFile const &colorFile, ColorData &data) const
306 307
   }
307 308
 }
308 309
 
310
+/// process update of value file, return true on update
311
+bool Game::valueUpdate(UIntFile &valueFile, ValueDescr const &descr,
312
+                       unsigned int &value)
313
+{
314
+  if (valueFile.checkModified()) {
315
+    valueFile.update();
316
+    valueFromFile(valueFile, descr, value);
317
+    return true;
318
+  } else {
319
+    return false;
320
+  }
321
+}
322
+
323
+/// get value from value file
324
+void Game::valueFromFile(UIntFile &valueFile, ValueDescr const &descr,
325
+                         unsigned int &value)
326
+{
327
+  if (! valueFile.m_valid) {
328
+    value = descr.default_;
329
+  } else {
330
+    value = valueFile.m_obj.m_uint;
331
+    if (value < descr.minimum) {
332
+      value = descr.minimum;
333
+    }
334
+    else if (value > descr.maximum) {
335
+      value = descr.maximum;
336
+    }
337
+  }
338
+}
339
+
309 340
 /// send current image buffer as frame to output stream
310 341
 void Game::sendFrame()
311 342
 {
... ...
@@ -19,6 +19,7 @@
19 19
 #include "Mgrs.h"
20 20
 #include "Module.h"
21 21
 #include "OutStreamFile.h"
22
+#include "UIntFile.h"
22 23
 
23 24
 namespace Blinker {
24 25
 
... ...
@@ -29,6 +30,13 @@ protected:
29 30
   /// raw color data matching image buffer
30 31
   typedef std::vector<unsigned char> ColorData;
31 32
 
33
+  /// descriptor of value (e.g. a setting for the game)
34
+  struct ValueDescr {
35
+    unsigned int default_;
36
+    unsigned int minimum;
37
+    unsigned int maximum;
38
+  };
39
+
32 40
 public:
33 41
   /**
34 42
    * @brief constructor
... ...
@@ -151,6 +159,14 @@ protected:
151 159
   /// convert color to raw color data
152 160
   void color2data(ColorFile const &colorFile, ColorData &data) const;
153 161
 
162
+  /// process update of value file, return true on update
163
+  static bool valueUpdate(UIntFile &valueFile, ValueDescr const &descr,
164
+                          unsigned int &value);
165
+
166
+  /// get value from value file
167
+  static void valueFromFile(UIntFile &valueFile, ValueDescr const &descr,
168
+                            unsigned int &value);
169
+
154 170
   /// send current image buffer as frame to output stream
155 171
   void sendFrame();
156 172
 
... ...
@@ -23,13 +23,17 @@
23 23
 #include "Pong.h"
24 24
 #include "Time.h"
25 25
 #include "TimeCallee.h"
26
+#include "UIntFile.h"
26 27
 
27 28
 namespace Blinker {
28 29
 
30
+/// descriptor for delay value
31
+Pong::ValueDescr const Pong::c_delayDescr = { 200, 100, 500 };
32
+
29 33
 /// operator connection name suffix for left player's connection
30
-std::string const Pong::OpConnSuffixLeft = "/left";
34
+std::string const Pong::c_opConnSuffixLeft = "/left";
31 35
 /// operator connection name suffix for right player's connection
32
-std::string const Pong::OpConnSuffixRight = "/right";
36
+std::string const Pong::c_opConnSuffixRight = "/right";
33 37
 
34 38
 /**
35 39
  * @brief constructor
... ...
@@ -45,24 +49,26 @@ Pong::Pong(const std::string &name, Mgrs &mgrs, const Directory &dirBase):
45 49
   m_fileComputerColor(dirBase.getFile("computerColor")),
46 50
   m_fileScoreColor(dirBase.getFile("scoreColor")),
47 51
   m_fileGoalColor(dirBase.getFile("goalColor")),
52
+  m_fileDelay(dirBase.getFile("delay")),
48 53
   m_ballColor(), m_lineColor(), m_padColor(), m_computerColor(),
49 54
   m_scoreColor(), m_goalColor(),
55
+  m_delay(c_delayDescr.default_),
50 56
   m_pConnLeft(NULL), m_pConnRight(NULL),
51 57
   m_ballPosX(-1), m_ballPosY(-1), m_ballDirX(0), m_ballDirY(0),
52 58
   m_padSize(0), m_leftPosY(0), m_rightPosY(0), m_leftDelay(0), m_rightDelay(0),
53 59
   m_goalDelay(0), m_bounceCnt(0), m_scoreLeft(0), m_scoreRight(0)
54 60
 {
55 61
   // open operator connection interfaces for left and right player
56
-  m_mgrs.m_opMgr.open(m_name + OpConnSuffixLeft, this);
57
-  m_mgrs.m_opMgr.open(m_name + OpConnSuffixRight, this);
62
+  m_mgrs.m_opMgr.open(m_name + c_opConnSuffixLeft, this);
63
+  m_mgrs.m_opMgr.open(m_name + c_opConnSuffixRight, this);
58 64
 }
59 65
 
60 66
 /// virtual destructor
61 67
 Pong::~Pong()
62 68
 {
63 69
   // close operator connection interfaces
64
-  m_mgrs.m_opMgr.close(m_name + OpConnSuffixLeft);
65
-  m_mgrs.m_opMgr.close(m_name + OpConnSuffixRight);
70
+  m_mgrs.m_opMgr.close(m_name + c_opConnSuffixLeft);
71
+  m_mgrs.m_opMgr.close(m_name + c_opConnSuffixRight);
66 72
 
67 73
   // close open operator connections
68 74
   if (m_pConnLeft) {
... ...
@@ -89,7 +95,8 @@ bool Pong::updateConfigGame()
89 95
       colorUpdate(m_filePadColor, m_padColor) ||
90 96
       colorUpdate(m_fileComputerColor, m_computerColor) ||
91 97
       colorUpdate(m_fileScoreColor, m_scoreColor) ||
92
-      colorUpdate(m_fileGoalColor, m_goalColor)) {
98
+      colorUpdate(m_fileGoalColor, m_goalColor) ||
99
+      valueUpdate(m_fileDelay, c_delayDescr, m_delay)) {
93 100
     ret = true;
94 101
   }
95 102
 
... ...
@@ -104,11 +111,11 @@ bool Pong::updateConfigGame()
104 111
 bool Pong::acceptNewOpConn(const std::string &name)
105 112
 {
106 113
   // left player can join if none there yet
107
-  if (name == m_name + OpConnSuffixLeft && ! m_pConnLeft) {
114
+  if (name == m_name + c_opConnSuffixLeft && ! m_pConnLeft) {
108 115
     return true;
109 116
   }
110 117
   // right player can join if none there yet
111
-  if (name == m_name + OpConnSuffixRight && ! m_pConnRight) {
118
+  if (name == m_name + c_opConnSuffixRight && ! m_pConnRight) {
112 119
     return true;
113 120
   }
114 121
   // default: reject connection
... ...
@@ -125,11 +132,11 @@ bool Pong::acceptNewOpConn(const std::string &name)
125 132
 void Pong::newOpConn(const std::string &name, OpConn *pConn)
126 133
 {
127 134
   // left player joins if none there yet
128
-  if (name == m_name + OpConnSuffixLeft && ! m_pConnLeft) {
135
+  if (name == m_name + c_opConnSuffixLeft && ! m_pConnLeft) {
129 136
     m_pConnLeft = pConn;
130 137
   }
131 138
   // right player joins if none there yet
132
-  else if (name == m_name + OpConnSuffixRight && ! m_pConnRight) {
139
+  else if (name == m_name + c_opConnSuffixRight && ! m_pConnRight) {
133 140
     m_pConnRight = pConn;
134 141
   }
135 142
   // nothing happens
... ...
@@ -223,6 +230,8 @@ void Pong::reinitialize()
223 230
   color2data(m_fileComputerColor, m_computerColor);
224 231
   color2data(m_fileScoreColor, m_scoreColor);
225 232
   color2data(m_fileGoalColor, m_goalColor);
233
+  // get values
234
+  valueFromFile(m_fileDelay, c_delayDescr, m_delay);
226 235
 
227 236
   // reset scores
228 237
   m_scoreLeft = 0;
... ...
@@ -566,8 +575,9 @@ void Pong::planTimeCall()
566 575
   }
567 576
 
568 577
   // compute interval based on score and bounce count
569
-  float speedup = 10 * (m_scoreLeft + m_scoreRight) + m_bounceCnt;
570
-  float interval = 0.05f + 0.1f * expf(-0.03f * speedup);
578
+  int speedup = 10 * (m_scoreLeft + m_scoreRight) + m_bounceCnt;
579
+  float scale = 0.3f + 0.7f * expf(-0.03f * speedup);
580
+  float interval = 1e-3f * m_delay * scale;
571 581
 
572 582
   // request next time call
573 583
   Time stepTime;
... ...
@@ -25,6 +25,7 @@
25 25
 #include "OutStreamFile.h"
26 26
 #include "Time.h"
27 27
 #include "TimeCallee.h"
28
+#include "UIntFile.h"
28 29
 
29 30
 namespace Blinker {
30 31
 
... ...
@@ -163,10 +164,13 @@ protected:
163 164
 
164 165
 protected:
165 166
 
167
+  /// descriptor for delay value
168
+  static ValueDescr const c_delayDescr;
169
+
166 170
   /// operator connection name suffix for left player's connection
167
-  static std::string const OpConnSuffixLeft;
171
+  static std::string const c_opConnSuffixLeft;
168 172
   /// operator connection name suffix for right player's connection
169
-  static std::string const OpConnSuffixRight;
173
+  static std::string const c_opConnSuffixRight;
170 174
 
171 175
   ColorFile m_fileBallColor;     ///< color file for ball color
172 176
   ColorFile m_fileLineColor;     ///< color file for center line
... ...
@@ -174,14 +178,19 @@ protected:
174 178
   ColorFile m_fileComputerColor; ///< color file for computer player pad
175 179
   ColorFile m_fileScoreColor;    ///< color file for score when ball is moving
176 180
   ColorFile m_fileGoalColor;     ///< color file for score during goal
181
+  UIntFile  m_fileDelay;         ///< file for initial delay in ms per frame
182
+
177 183
   ColorData    m_ballColor;     ///< ball color
178 184
   ColorData    m_lineColor;     ///< center line color
179 185
   ColorData    m_padColor;      ///< phone player pad color
180 186
   ColorData    m_computerColor; ///< computer player pad color
181 187
   ColorData    m_scoreColor;    ///< score color when ball is moving
182 188
   ColorData    m_goalColor;     ///< score color during goal
189
+  unsigned int m_delay;         ///< initial delay in ms per frame (ball speed)
190
+
183 191
   OpConn *m_pConnLeft;  ///< operator connection left player (or NULL)
184
-  OpConn   *m_pConnRight;        ///< operator connection right player (o NULL)
192
+  OpConn *m_pConnRight; ///< operator connection right player (or NULL)
193
+
185 194
   int m_ballPosX;   ///< ball position X
186 195
   int m_ballPosY;   ///< ball position Y
187 196
   int m_ballDirX;   ///< ball direction X
188 197