63dfd259223551b1e767e3b34444ecfdf1bf5944
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

1) /* Blinker
2)    Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

6) #include <cmath>
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

7) #include <stdlib.h>
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

8) #include <string>
9) #include <vector>
10) 
11) #include <BlinkenLib/BlinkenFrame.h>
12) 
13) #include "File.h"
14) #include "Format.h"
15) #include "FormatFile.h"
16) #include "Game.h"
17) #include "Mgrs.h"
18) #include "Module.h"
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

19) #include "OpConn.h"
20) #include "OpConnIf.h"
21) #include "OpReqIf.h"
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

22) #include "OutStreamFile.h"
23) #include "Pong.h"
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

24) #include "Time.h"
25) #include "TimeCallee.h"
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

26) #include "UIntFile.h"
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

27) 
28) namespace Blinker {
29) 
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

30) /// descriptor for delay value
31) Pong::ValueDescr const Pong::c_delayDescr = { 200, 100, 500 };
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

32) /// descriptor for maximum score value
33) Pong::ValueDescr const Pong::c_maxScoreDescr = { 9, 1, 99 };
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

34) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

35) /// operator connection name suffix for left player's connection
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

36) std::string const Pong::c_opConnSuffixLeft = "/left";
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

37) /// operator connection name suffix for right player's connection
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

38) std::string const Pong::c_opConnSuffixRight = "/right";
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

39) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

40) /**
41)  * @brief constructor
42)  * @param[in] name module name
43)  * @param[in] mgrs managers
44)  * @param[in] dirBase base directory
45)  */
46) Pong::Pong(const std::string &name, Mgrs &mgrs, const Directory &dirBase):
47)   Game(name, mgrs, dirBase),
48)   m_fileBallColor(dirBase.getFile("ballColor")),
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

49)   m_fileLineColor(dirBase.getFile("lineColor")),
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

50)   m_filePadColor(dirBase.getFile("padColor")),
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

51)   m_fileComputerColor(dirBase.getFile("computerColor")),
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

52)   m_fileScoreColor(dirBase.getFile("scoreColor")),
53)   m_fileGoalColor(dirBase.getFile("goalColor")),
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

54)   m_fileDelay(dirBase.getFile("delay")),
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

55)   m_fileMaxScore(dirBase.getFile("maxScore")),
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

56)   m_ballColor(), m_lineColor(), m_padColor(), m_computerColor(),
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

57)   m_scoreColor(), m_goalColor(),
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

58)   m_delay(c_delayDescr.default_), m_maxScore(c_maxScoreDescr.default_),
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

59)   m_pConnLeft(NULL), m_pConnRight(NULL),
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

60)   m_ballPosX(-1), m_ballPosY(-1), m_ballDirX(0), m_ballDirY(0),
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

61)   m_padSize(0), m_leftPosY(0), m_rightPosY(0), m_leftDelay(0), m_rightDelay(0),
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

62)   m_goalDelay(0), m_bounceCnt(0), m_scoreLeft(0), m_scoreRight(0)
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

63) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

64)   // open operator connection interfaces for left and right player
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

65)   m_mgrs.m_opMgr.open(m_name + c_opConnSuffixLeft, this);
66)   m_mgrs.m_opMgr.open(m_name + c_opConnSuffixRight, this);
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

67) }
68) 
69) /// virtual destructor
70) Pong::~Pong()
71) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

72)   // close operator connection interfaces
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

73)   m_mgrs.m_opMgr.close(m_name + c_opConnSuffixLeft);
74)   m_mgrs.m_opMgr.close(m_name + c_opConnSuffixRight);
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

75) 
76)   // close open operator connections
77)   if (m_pConnLeft) {
78)     m_pConnLeft->close();
79)     m_pConnLeft = NULL;
80)   }
81)   if (m_pConnRight) {
82)     m_pConnRight->close();
83)     m_pConnRight = NULL;
84)   }
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

85) }
86) 
87) /// check for update of configuration (derived game), return true on update
88) bool Pong::updateConfigGame()
89) {
90)   bool ret = false;
91) 
92)   // color file was modified -> convert color, return true for update
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

93)   if (colorUpdate(m_fileBallColor, m_ballColor) ||
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

94)       colorUpdate(m_fileLineColor, m_lineColor) ||
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

95)       colorUpdate(m_filePadColor, m_padColor) ||
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

96)       colorUpdate(m_fileComputerColor, m_computerColor) ||
97)       colorUpdate(m_fileScoreColor, m_scoreColor) ||
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

98)       colorUpdate(m_fileGoalColor, m_goalColor) ||
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

99)       valueUpdate(m_fileDelay, c_delayDescr, m_delay) ||
100)       valueUpdate(m_fileMaxScore, c_maxScoreDescr, m_maxScore)) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

101)     ret = true;
102)   }
103) 
104)   return ret;
105) }
106) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

107) /**
Stefan Schuermans fix comment typo

Stefan Schuermans authored 5 years ago

108)  * @brief check if accepting new operator connection is possible
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

109)  * @param[in] name operator interface name
110)  * @return if accepting new connection is possible
111)  */
112) bool Pong::acceptNewOpConn(const std::string &name)
113) {
114)   // left player can join if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

115)   if (name == m_name + c_opConnSuffixLeft && ! m_pConnLeft) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

116)     return true;
117)   }
118)   // right player can join if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

119)   if (name == m_name + c_opConnSuffixRight && ! m_pConnRight) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

120)     return true;
121)   }
122)   // default: reject connection
123)   return false;
124) }
125) 
126) /**
127)  * @brief new operator connection
128)  * @param[in] name operator interface name
129)  * @param[in] pConn operator connection object
130)  *
131)  * The new connection may not yet be used for sending inside this callback.
132)  */
133) void Pong::newOpConn(const std::string &name, OpConn *pConn)
134) {
135)   // left player joins if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

136)   if (name == m_name + c_opConnSuffixLeft && ! m_pConnLeft) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

137)     m_pConnLeft = pConn;
138)   }
139)   // right player joins if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

140)   else if (name == m_name + c_opConnSuffixRight && ! m_pConnRight) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

141)     m_pConnRight = pConn;
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

142)   }
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

143)   // close imcoming connection as soon as possible, nothing else happens
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

144)   else {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

145)     requestOpConnClose(pConn);
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

146)     return;
147)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

148) 
149)   // already active
150)   if (isActive()) {
151)     redraw(); // player color is different for phone / computer
152)   }
153)   // first player joined
154)   else {
155)     activate();
156)   }
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

157) }
158) 
159) /**
160)  * @brief key command received on operator connection
161)  * @param[in] pConn operator connection object
162)  * @param[in] key key that was pressed
163)  */
164) void Pong::opConnRecvKey(OpConn *pConn, char key)
165) {
166)   // left player
167)   if (pConn == m_pConnLeft) {
168)     processKey(key, m_leftPosY);
169)   }
170)   // right player
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

171)   else if (pConn == m_pConnRight) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

172)     processKey(key, m_rightPosY);
173)   }
174) }
175) 
176) /**
177)  * @brief play command received on operator connection
178)  * @param[in] pConn operator connection object
179)  * @param[in] sound name of sound to play
180)  */
181) void Pong::opConnRecvPlay(OpConn *pConn, const std::string &sound)
182) {
183)   (void)pConn;
184)   (void)sound;
185) }
186) 
187) /**
188)  * @brief operator connection is closed
189)  * @param[in] pConn operator connection object
190)  *
191)  * The connection may not be used for sending any more in this callback.
192)  */
193) void Pong::opConnClose(OpConn *pConn)
194) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

195)   // remove coperator connection from requests (if it was in)
196)   forgetOpConn(pConn);
197) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

198)   // left player leaves
199)   if (pConn == m_pConnLeft) {
200)     m_pConnLeft = NULL;
201)   }
202)   // right player leaves
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

203)   else if (pConn == m_pConnRight) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

204)     m_pConnRight = NULL;
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

205)   }
206)   // nothing happens
207)   else {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

208)     return;
209)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

210) 
211)   // still a phone player there
212)   if (m_pConnLeft || m_pConnRight) {
213)     redraw(); // player color is different for phone / computer
214)   }
215)   // no phone players left
216)   else {
217)     deactivate();
218)   }
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

219) }
220) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

221) /// re-initialize game (e.g. due to config change)
222) void Pong::reinitialize()
223) {
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

224)   // compute parameters
225)   m_padSize = (m_height + 1) / 3;
226)   m_leftPosY = (m_height - m_padSize) / 2;
227)   m_rightPosY = (m_height - m_padSize) / 2;
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

228)   m_leftDelay = 0;
229)   m_rightDelay = 0;
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

230) 
231)   // convert colors
232)   color2data(m_fileBallColor, m_ballColor);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

233)   color2data(m_fileLineColor, m_lineColor);
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

234)   color2data(m_filePadColor, m_padColor);
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

235)   color2data(m_fileComputerColor, m_computerColor);
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

236)   color2data(m_fileScoreColor, m_scoreColor);
237)   color2data(m_fileGoalColor, m_goalColor);
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

238)   // get values
239)   valueFromFile(m_fileDelay, c_delayDescr, m_delay);
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

240)   valueFromFile(m_fileMaxScore, c_maxScoreDescr, m_maxScore);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

241) 
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

242)   // reset scores
243)   m_scoreLeft = 0;
244)   m_scoreRight = 0;
245) 
246)   // start first ball
Stefan Schuermans pong: start ball at side

Stefan Schuermans authored 5 years ago

247)   m_ballDirX = 0; // start at random side
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

248)   startBall();
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

249) }
250) 
251) /// redraw current game image, expected to call sendFrame() at end
252) void Pong::redraw()
253) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

254)   int y, x;
255) 
256)   // draw background
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

257)   rectFill(0, m_height, 0, m_width, m_backgroundColor);
258) 
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

259)   // draw middle line: single line on odd width, two dashed lines at even width
260)   for (y = 0; y < m_height; ++y) {
261)     x = (m_width - (y & 1)) / 2;
262)     pixel(y, x, m_lineColor);
263)   }
264) 
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

265)   // draw score
266)   ColorData const &scoreColor = m_goalDelay <= 0 ? m_scoreColor : m_goalColor;
267)   y = (m_height - 1) / 2;
268)   x = m_width / 4;
269)   number3x5(y, x, 0, 0, m_scoreLeft, scoreColor);
270)   number3x5(y, m_width - 1 - x, 0, 0, m_scoreRight, scoreColor);
271) 
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

272)   // draw pads
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

273)   lineVert(m_leftPosY, m_leftPosY + m_padSize - 1, 0,
274)            m_pConnLeft ? m_padColor : m_computerColor);
275)   lineVert(m_rightPosY, m_rightPosY + m_padSize - 1, m_width - 1,
276)            m_pConnRight ? m_padColor : m_computerColor);
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

277) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

278)   // draw ball (blinking if goal delay is active)
279)   if (m_goalDelay <= 0 || (m_goalDelay & 4) == 0) {
280)       pixel(m_ballPosY, m_ballPosX, m_ballColor);
281)   }
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

282) 
283)   // send updated image buffer as frame
284)   sendFrame();
285) }
286) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

287) /// process next time step of game
288) void Pong::timeStep()
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

289) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

290)   // game is running
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

291)   if (m_goalDelay <= 0) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

292) 
293)     // computer player: move pads
294)     if (! m_pConnLeft) {
295)       computerLeft();
296)     }
297)     if (! m_pConnRight) {
298)       computerRight();
299)     }
300) 
301)     // bounce ball
302)     bounceBall();
303) 
304)     // move ball
305)     m_ballPosX += m_ballDirX;
306)     m_ballPosY += m_ballDirY;
307) 
308)     // detect goal
309)     detectGoal();
310) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

311)   }
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

312)   // goal delay (blinking ball)
313)   else if (m_goalDelay > 0) {
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

314) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

315)     --m_goalDelay;
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

316) 
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

317)     // delay is over
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

318)     if (m_goalDelay <= 0) {
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

319)         // maximum score reached
320)         if (m_scoreLeft >= (int)m_maxScore ||
321)             m_scoreRight >= (int)m_maxScore) {
322)           gameOver();
323)           return; // no gameOver() calls deactivate(), no need to redraw
324)         }
325)         // game continues with new ball
326)         else {
327)           startBall();
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

328)           return; // startBall() calls redraw() and planTimeStep()
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

329)         }
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

330)     }
331) 
332)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

333) 
334)   // draw and send frame
335)   redraw();
336) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

337)   // request next time step
338)   planTimeStep();
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

339) }
340) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

341) /**
342)  * @brief process key received from phone player
343)  * @param[in] key received key from player
344)  * @param[in,out] padPosY y position of player's pad
345)  */
346) void Pong::processKey(char key, int &padPosY)
347) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

348)   // do not move pad if goal delay is active
349)   if (m_goalDelay > 0) {
350)     return;
351)   }
352) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

353)   // move pad (2 = up, 8 = down), do not move pad out of field
354)   if (key == '2' && padPosY > 0) {
355)     --padPosY;
356)     redraw();
357)   }
358)   else if (key == '8' && padPosY < m_height - m_padSize) {
359)     ++padPosY;
360)     redraw();
361)   }
362) }
363) 
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

364) /**
365)  * @brief delay processing for computer players
366)  * @param[in,out] delay delay variable of computer player
367)  * @return whether computer player is allowed to move
368)  */
369) bool Pong::computerDelay(int &delay) const
370) 
371) {
372)   // zero delay: generate new delay
373)   if (delay <= 0) {
374)     int avg_steps = (m_height - m_padSize) / 2;
375)     int delay_range = avg_steps > 1 ? m_width / avg_steps: m_width;
376)     delay = rand() % delay_range + delay_range;
377)   }
378) 
379)   // count down delay
380)   --delay;
381) 
382)   // moving allowd if delay expired
383)   return delay <= 0;
384) }
385) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

386) /**
387)  * @brief computation of ideal pad position for computer players
388)  * @param[in] padBallX x coordinate of position of ball when hitting the pad
389)  * @param[in] padY current y coordinate of pad
390)  * @param[out] padYmin minimum ideal y position of pad
391)  * @param[out] padYmax maximum ideal y position of pad
392)  */
393) void Pong::computerComputePadPos(int padBallX, int padY,
394)                                  int &padYmin, int &padYmax) const
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

395) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

396)   // ball not moving towards pad
397)   if ((padBallX - m_ballPosX) * m_ballDirX <= 0) {
398)     // do not move if ball is still close to pad
399)     if (abs(padBallX - m_ballPosX) <= 2) {
400)       padYmin = padY;
401)       padYmax = padY;
402)       return;
403)     }
404)     // move pad to middle (might be 2 pixels wide)
405)     padYmin = (m_height - m_padSize) / 2;
406)     padYmax = (m_height - m_padSize + 1) / 2;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

407)     return;
408)   }
409) 
410)   // compute expected ball position at pad
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

411)   int ballPosX = m_ballPosX; // simulate were ball is going
412)   int ballPosY = m_ballPosY;
413)   int ballDirY = m_ballDirY;
414)   while ((padBallX - ballPosX) * m_ballDirX > 0) { // while moving to pad
415)     int deltaX = padBallX - ballPosX;
416)     int deltaY = deltaX * m_ballDirX * ballDirY;
417)     if (deltaY < -ballPosY) {
418)       deltaY = -ballPosY;
419)       ballPosX += deltaY * m_ballDirX * ballDirY;
420)       ballPosY = 0;
421)       ballDirY = 1;
422)     }
423)     else if (deltaY > m_height - 1 - ballPosY) {
424)       deltaY = m_height - 1 - ballPosY;
425)       ballPosX += deltaY * m_ballDirX * ballDirY;
426)       ballPosY = m_height - 1;
427)       ballDirY = -1;
428)     } else {
429)       ballPosX += deltaX;
430)       ballPosY += deltaY;
431)     }
432)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

433) 
434)   // compute pad position to hit ball with center of pad
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

435)   padYmin = ballPosY - m_padSize / 2;
436)   padYmax = ballPosY - (m_padSize - 1) / 2;
437) }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

438) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

439) /**
440)  * @brief move pad for computer players
441)  * @param[in] padYmin minimum desired y position of pad
442)  * @param[in] padYmax maximum desired y position of pad
443)  * @param[in,out] padPosY y position of pad
444)  */
445) void Pong::computerMovePad(int padYmin, int padYmax, int &padPosY) const
446) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

447)   // do not move pad if goal delay is active
448)   if (m_goalDelay > 0) {
449)     return;
450)   }
451) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

452)   // move pad, do not move pad out of field
453)   if (padPosY > padYmax && padPosY > 0) {
454)     --padPosY;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

455)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

456)   else if (padPosY < padYmin && padPosY < m_height - m_padSize) {
457)     ++padPosY;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

458)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

459) }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

460) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

461) /// computer player for left pad
462) void Pong::computerLeft()
463) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

464)   if (computerDelay(m_leftDelay)) {
465)     int padYmin, padYmax;
466)     computerComputePadPos(1, m_leftPosY, padYmin, padYmax);
467)     computerMovePad(padYmin, padYmax, m_leftPosY);
468)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

469) }
470) 
471) /// computer player for right pad
472) void Pong::computerRight()
473) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

474)   if (computerDelay(m_rightDelay)) {
475)     int padYmin, padYmax;
476)     computerComputePadPos(m_width - 2, m_rightPosY, padYmin, padYmax);
477)     computerMovePad(padYmin, padYmax, m_rightPosY);
478)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

479) }
480) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

481) /// bounce ball
482) void Pong::bounceBall()
483) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

484)   bounceBallSide(); // must be done before player bounce to be safe
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

485)   bounceBallLeft();
486)   bounceBallRight();
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

487)   bounceBallSide(); // must also be done after player bounce to be safe
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

488) }
489) 
490) /// bounce ball at sides
491) void Pong::bounceBallSide()
492) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

493)   if (m_ballPosY <= 0 && m_ballDirY < 0) {
494)     m_ballDirY = 1;
495)   }
496)   if (m_ballPosY >= m_height - 1 && m_ballDirY > 0) {
497)     m_ballDirY = -1;
498)   }
499)   if (m_ballPosX <= 0 && m_ballDirX < 0) {
500)     m_ballDirX = 1;
501)   }
502)   if (m_ballPosX >= m_width - 1 && m_ballDirX > 0) {
503)     m_ballDirX = -1;
504)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

505) }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

506) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

507) /// bounce ball at left pad
508) void Pong::bounceBallLeft()
509) {
510)   if (m_ballPosX != 1 || m_ballDirX >= 0) {
511)     return;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

512)   }
513) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

514)   // top corner
515)   if (m_ballPosY == m_leftPosY - 1 && m_ballDirY > 0) {
516)     m_ballDirX = 1;
517)     m_ballDirY = -1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

518)     ++m_bounceCnt;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

519)   }
520) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

521)   // bottom corner
522)   else if (m_ballPosY == m_leftPosY + m_padSize && m_ballDirY < 0) {
523)     m_ballDirX = 1;
524)     m_ballDirY = 1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

525)     ++m_bounceCnt;
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

526)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

527) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

528)   // pad edge
529)   else if (m_ballPosY >= m_leftPosY &&
530)            m_ballPosY < m_leftPosY + m_padSize) {
531)     m_ballDirX = 1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

532)     ++m_bounceCnt;
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

533)   }
534) }
535) 
536) /// bounce ball at right pad
537) void Pong::bounceBallRight()
538) {
539)   if (m_ballPosX != m_width - 2 || m_ballDirX <= 0) {
540)     return;
541)   }
542) 
543)   // top corner
544)   if (m_ballPosY == m_rightPosY - 1 && m_ballDirY > 0) {
545)     m_ballDirX = -1;
546)     m_ballDirY = -1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

547)     ++m_bounceCnt;
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

548)   }
549) 
550)   // bottom corner
551)   else if (m_ballPosY == m_rightPosY + m_padSize && m_ballDirY < 0) {
552)     m_ballDirX = -1;
553)     m_ballDirY = 1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

554)     ++m_bounceCnt;
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

555)   }
556) 
557)   // pad edge
558)   else if (m_ballPosY >= m_rightPosY &&
559)            m_ballPosY < m_rightPosY + m_padSize) {
560)     m_ballDirX = -1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

561)     ++m_bounceCnt;
562)   }
563) }
564) 
565) /// detect goal
566) void Pong::detectGoal()
567) {
568)   static int goalBlinkCnt = 3;
569)   static int goalDelay = goalBlinkCnt * 8 + 3;
570) 
571)   // ball at far left - goal for right player
572)   if (m_ballPosX == 0) {
573)     m_goalDelay = goalDelay;
574)     ++m_scoreRight;
575)   }
576) 
577)   // ball at far right - goal for left player
578)   else if (m_ballPosX == m_width - 1) {
579)     m_goalDelay = goalDelay;
580)     ++m_scoreLeft;
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

581)   }
582) }
583) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

584) /// set time for next time step of game - or unset if not needed
585) void Pong::planTimeStep()
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

586) {
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

587)   // no time call needed if not active
588)   if (! isActive()) {
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

589)     unsetTimeStep();
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

590)     return;
591)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

592) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

593)   // compute interval based on score and bounce count
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

594)   int speedup = 10 * (m_scoreLeft + m_scoreRight) + m_bounceCnt;
595)   float scale = 0.3f + 0.7f * expf(-0.03f * speedup);
596)   float interval = 1e-3f * m_delay * scale;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

597) 
598)   // request next time call
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

599)   Time stepTime;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

600)   stepTime.fromFloatSec(interval);
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

601)   setTimeStep(Time::now() + stepTime);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

602) }
603) 
604) /// start ball
605) void Pong::startBall()
606) {
Stefan Schuermans pong: start ball at side

Stefan Schuermans authored 5 years ago

607)   // horizontal start direction opposite as before goal or random
608)   if (m_ballDirX > 0) {
609)     m_ballDirX = -1;
610)   } else if (m_ballDirX < 0) {
611)     m_ballDirX = 1;
612)   } else {
613)     m_ballDirX = (rand() & 1) * 2 - 1;
614)   }
615)   // random vertical start direction
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

616)   m_ballDirY = (rand() & 1) * 2 - 1;
617) 
Stefan Schuermans pong: start ball at side

Stefan Schuermans authored 5 years ago

618)   // horizontal start postion at side of field (depending on direction)
619)   m_ballPosX = m_ballDirX > 0 ? 0 : m_width - 1;
620)   // random vertical start position
621)   m_ballPosY = rand() % m_height;
622) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

623)   // no delays, ball has not bounced at pad
624)   m_leftDelay = 0;
625)   m_rightDelay = 0;
626)   m_goalDelay = 0;
627)   m_bounceCnt = 0;
628) 
629)   // draw and send frame
630)   redraw();
631) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

632)   // request first time step if needed
633)   planTimeStep();
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

634) }
635) 
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

636) /// game over: close player connections and deactivate
637) void Pong::gameOver()
638) {
639)   // close open operator connections
640)   if (m_pConnLeft) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

641)     forgetOpConn(m_pConnLeft); // remove from requests (if it was in)
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

642)     m_pConnLeft->close();
643)     m_pConnLeft = NULL;
644)   }
645)   if (m_pConnRight) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

646)     forgetOpConn(m_pConnRight); // remove from requests (if it was in)
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

647)     m_pConnRight->close();
648)     m_pConnRight = NULL;
649)   }
650) 
651)   // deactivate game
652)   deactivate();
653) }
654)