8ab4f192e3a0ce5a9d28b1c8f4c5369429ffc659
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 sound support for pong game

Stefan Schuermans authored 5 years ago

19) #include "NameFile.h"
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

28) 
29) namespace Blinker {
30) 
31) /**
32)  * @brief constructor
33)  * @param[in] name module name
34)  * @param[in] mgrs managers
35)  * @param[in] dirBase base directory
36)  */
37) Pong::Pong(const std::string &name, Mgrs &mgrs, const Directory &dirBase):
38)   Game(name, mgrs, dirBase),
39)   m_fileBallColor(dirBase.getFile("ballColor")),
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

46)   m_fileMaxScore(dirBase.getFile("maxScore")),
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

47)   m_fileLeftPlayerSound(dirBase.getFile("leftPlayerSound")),
48)   m_fileRightPlayerSound(dirBase.getFile("rightPlayerSound")),
49)   m_fileScoreSound(dirBase.getFile("scoreSound")),
50)   m_fileOtherScoreSound(dirBase.getFile("otherScoreSound")),
51)   m_fileWinSound(dirBase.getFile("winSound")),
52)   m_fileLoseSound(dirBase.getFile("loseSound")),
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

58)   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

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

Stefan Schuermans authored 5 years ago

60) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

64) }
65) 
66) /// virtual destructor
67) Pong::~Pong()
68) {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

82) }
83) 
84) /// check for update of configuration (derived game), return true on update
85) bool Pong::updateConfigGame()
86) {
87)   bool ret = false;
88) 
89)   // color file was modified -> convert color, return true for update
Stefan Schuermans improve comment

Stefan Schuermans authored 5 years ago

90)   // cfg value file was updated -> read new cfg value, return true for update
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

94)       colorUpdate(m_fileComputerColor, m_computerColor) ||
95)       colorUpdate(m_fileScoreColor, m_scoreColor) ||
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

99)     ret = true;
100)   }
101) 
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

102)   // sound name file was modified -> re-read sound name, no other update needed
103)   soundUpdate(m_fileLeftPlayerSound);
104)   soundUpdate(m_fileRightPlayerSound);
105)   soundUpdate(m_fileScoreSound);
106)   soundUpdate(m_fileOtherScoreSound);
107)   soundUpdate(m_fileWinSound);
108)   soundUpdate(m_fileLoseSound);
109) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

110)   return ret;
111) }
112) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

113) /**
Stefan Schuermans fix comment typo

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

115)  * @param[in] name operator interface name
116)  * @return if accepting new connection is possible
117)  */
118) bool Pong::acceptNewOpConn(const std::string &name)
119) {
120)   // left player can join if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

122)     return true;
123)   }
124)   // right player can join if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

143)     m_pConnLeft = pConn;
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

144)     requestOpConnSound(m_pConnLeft, m_fileLeftPlayerSound);
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

145)   }
146)   // right player joins if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

148)     m_pConnRight = pConn;
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

149)     requestOpConnSound(m_pConnRight, m_fileRightPlayerSound);
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

150)   }
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

152)   else {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

154)     return;
155)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

156) 
157)   // already active
158)   if (isActive()) {
159)     redraw(); // player color is different for phone / computer
160)   }
161)   // first player joined
162)   else {
163)     activate();
164)   }
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

165) }
166) 
167) /**
168)  * @brief key command received on operator connection
169)  * @param[in] pConn operator connection object
170)  * @param[in] key key that was pressed
171)  */
172) void Pong::opConnRecvKey(OpConn *pConn, char key)
173) {
Stefan Schuermans pong: hash -> hangup, star...

Stefan Schuermans authored 5 years ago

174)   // hash -> hang up
175)   if (key == '#') {
176)     opConnClose(pConn);
177)     pConn->close();
178)     return;
179)   }
180) 
181)   // star -> inform player about it side
182)   if (key == '*') {
183)     if (pConn == m_pConnLeft) {
184)       playOpConnSound(pConn, m_fileLeftPlayerSound);
185)     } else if (pConn == m_pConnRight) {
186)       playOpConnSound(pConn, m_fileRightPlayerSound);
187)     }
188)     return;
189)   }
190) 
191)   // normal keys for controlling game
192) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

193)   // left player
194)   if (pConn == m_pConnLeft) {
195)     processKey(key, m_leftPosY);
196)   }
197)   // right player
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

199)     processKey(key, m_rightPosY);
200)   }
201) }
202) 
203) /**
204)  * @brief play command received on operator connection
205)  * @param[in] pConn operator connection object
206)  * @param[in] sound name of sound to play
207)  */
208) void Pong::opConnRecvPlay(OpConn *pConn, const std::string &sound)
209) {
210)   (void)pConn;
211)   (void)sound;
212) }
213) 
214) /**
215)  * @brief operator connection is closed
216)  * @param[in] pConn operator connection object
217)  *
218)  * The connection may not be used for sending any more in this callback.
219)  */
220) void Pong::opConnClose(OpConn *pConn)
221) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

222)   // remove coperator connection from requests (if it was in)
223)   forgetOpConn(pConn);
224) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

225)   // left player leaves
226)   if (pConn == m_pConnLeft) {
227)     m_pConnLeft = NULL;
228)   }
229)   // right player leaves
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

232)   }
233)   // nothing happens
234)   else {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

235)     return;
236)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

237) 
238)   // still a phone player there
239)   if (m_pConnLeft || m_pConnRight) {
240)     redraw(); // player color is different for phone / computer
241)   }
242)   // no phone players left
243)   else {
244)     deactivate();
245)   }
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

246) }
247) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

251)   // compute parameters
252)   m_padSize = (m_height + 1) / 3;
253)   m_leftPosY = (m_height - m_padSize) / 2;
254)   m_rightPosY = (m_height - m_padSize) / 2;
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

255)   m_leftDelay = 0;
256)   m_rightDelay = 0;
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

257) 
258)   // convert colors
259)   color2data(m_fileBallColor, m_ballColor);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

263)   color2data(m_fileScoreColor, m_scoreColor);
264)   color2data(m_fileGoalColor, m_goalColor);
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

269)   // reset scores
270)   m_scoreLeft = 0;
271)   m_scoreRight = 0;
272) 
273)   // start first ball
Stefan Schuermans pong: start ball at side

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

276) }
277) 
278) /// redraw current game image, expected to call sendFrame() at end
279) void Pong::redraw()
280) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

281)   int y, x;
282) 
283)   // draw background
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

286)   // draw middle line: single line on odd width, two dashed lines at even width
287)   for (y = 0; y < m_height; ++y) {
288)     x = (m_width - (y & 1)) / 2;
289)     pixel(y, x, m_lineColor);
290)   }
291) 
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

292)   // draw score
293)   ColorData const &scoreColor = m_goalDelay <= 0 ? m_scoreColor : m_goalColor;
294)   y = (m_height - 1) / 2;
295)   x = m_width / 4;
296)   number3x5(y, x, 0, 0, m_scoreLeft, scoreColor);
297)   number3x5(y, m_width - 1 - x, 0, 0, m_scoreRight, scoreColor);
298) 
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

300)   lineVert(m_leftPosY, m_leftPosY + m_padSize - 1, 0,
301)            m_pConnLeft ? m_padColor : m_computerColor);
302)   lineVert(m_rightPosY, m_rightPosY + m_padSize - 1, m_width - 1,
303)            m_pConnRight ? m_padColor : m_computerColor);
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

304) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

309) 
310)   // send updated image buffer as frame
311)   sendFrame();
312) }
313) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

319) 
320)     // computer player: move pads
321)     if (! m_pConnLeft) {
322)       computerLeft();
323)     }
324)     if (! m_pConnRight) {
325)       computerRight();
326)     }
327) 
328)     // bounce ball
329)     bounceBall();
330) 
331)     // move ball
332)     m_ballPosX += m_ballDirX;
333)     m_ballPosY += m_ballDirY;
334) 
335)     // detect goal
336)     detectGoal();
337) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

341) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

346)         // maximum score reached
347)         if (m_scoreLeft >= (int)m_maxScore ||
348)             m_scoreRight >= (int)m_maxScore) {
349)           gameOver();
350)           return; // no gameOver() calls deactivate(), no need to redraw
351)         }
352)         // game continues with new ball
353)         else {
354)           startBall();
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

357)     }
358) 
359)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

360) 
361)   // draw and send frame
362)   redraw();
363) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

366) }
367) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

368) /**
369)  * @brief process key received from phone player
370)  * @param[in] key received key from player
371)  * @param[in,out] padPosY y position of player's pad
372)  */
373) void Pong::processKey(char key, int &padPosY)
374) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

375)   // do not move pad if goal delay is active
376)   if (m_goalDelay > 0) {
377)     return;
378)   }
379) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

380)   // move pad (2 = up, 8 = down), do not move pad out of field
381)   if (key == '2' && padPosY > 0) {
382)     --padPosY;
383)     redraw();
384)   }
385)   else if (key == '8' && padPosY < m_height - m_padSize) {
386)     ++padPosY;
387)     redraw();
388)   }
389) }
390) 
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

391) /**
392)  * @brief delay processing for computer players
393)  * @param[in,out] delay delay variable of computer player
394)  * @return whether computer player is allowed to move
395)  */
396) bool Pong::computerDelay(int &delay) const
397) 
398) {
399)   // zero delay: generate new delay
400)   if (delay <= 0) {
401)     int avg_steps = (m_height - m_padSize) / 2;
402)     int delay_range = avg_steps > 1 ? m_width / avg_steps: m_width;
403)     delay = rand() % delay_range + delay_range;
404)   }
405) 
406)   // count down delay
407)   --delay;
408) 
409)   // moving allowd if delay expired
410)   return delay <= 0;
411) }
412) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

413) /**
414)  * @brief computation of ideal pad position for computer players
415)  * @param[in] padBallX x coordinate of position of ball when hitting the pad
416)  * @param[in] padY current y coordinate of pad
417)  * @param[out] padYmin minimum ideal y position of pad
418)  * @param[out] padYmax maximum ideal y position of pad
419)  */
420) void Pong::computerComputePadPos(int padBallX, int padY,
421)                                  int &padYmin, int &padYmax) const
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

422) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

423)   // ball not moving towards pad
424)   if ((padBallX - m_ballPosX) * m_ballDirX <= 0) {
425)     // do not move if ball is still close to pad
426)     if (abs(padBallX - m_ballPosX) <= 2) {
427)       padYmin = padY;
428)       padYmax = padY;
429)       return;
430)     }
431)     // move pad to middle (might be 2 pixels wide)
432)     padYmin = (m_height - m_padSize) / 2;
433)     padYmax = (m_height - m_padSize + 1) / 2;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

434)     return;
435)   }
436) 
437)   // compute expected ball position at pad
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

438)   int ballPosX = m_ballPosX; // simulate were ball is going
439)   int ballPosY = m_ballPosY;
440)   int ballDirY = m_ballDirY;
441)   while ((padBallX - ballPosX) * m_ballDirX > 0) { // while moving to pad
442)     int deltaX = padBallX - ballPosX;
443)     int deltaY = deltaX * m_ballDirX * ballDirY;
444)     if (deltaY < -ballPosY) {
445)       deltaY = -ballPosY;
446)       ballPosX += deltaY * m_ballDirX * ballDirY;
447)       ballPosY = 0;
448)       ballDirY = 1;
449)     }
450)     else if (deltaY > m_height - 1 - ballPosY) {
451)       deltaY = m_height - 1 - ballPosY;
452)       ballPosX += deltaY * m_ballDirX * ballDirY;
453)       ballPosY = m_height - 1;
454)       ballDirY = -1;
455)     } else {
456)       ballPosX += deltaX;
457)       ballPosY += deltaY;
458)     }
459)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

462)   padYmin = ballPosY - m_padSize / 2;
463)   padYmax = ballPosY - (m_padSize - 1) / 2;
464) }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

465) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

466) /**
467)  * @brief move pad for computer players
468)  * @param[in] padYmin minimum desired y position of pad
469)  * @param[in] padYmax maximum desired y position of pad
470)  * @param[in,out] padPosY y position of pad
471)  */
472) void Pong::computerMovePad(int padYmin, int padYmax, int &padPosY) const
473) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

474)   // do not move pad if goal delay is active
475)   if (m_goalDelay > 0) {
476)     return;
477)   }
478) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

482)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

485)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

487) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

488) /// computer player for left pad
489) void Pong::computerLeft()
490) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

491)   if (computerDelay(m_leftDelay)) {
492)     int padYmin, padYmax;
493)     computerComputePadPos(1, m_leftPosY, padYmin, padYmax);
494)     computerMovePad(padYmin, padYmax, m_leftPosY);
495)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

496) }
497) 
498) /// computer player for right pad
499) void Pong::computerRight()
500) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

501)   if (computerDelay(m_rightDelay)) {
502)     int padYmin, padYmax;
503)     computerComputePadPos(m_width - 2, m_rightPosY, padYmin, padYmax);
504)     computerMovePad(padYmin, padYmax, m_rightPosY);
505)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

508) /// bounce ball
509) void Pong::bounceBall()
510) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

512)   bounceBallLeft();
513)   bounceBallRight();
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

515) }
516) 
517) /// bounce ball at sides
518) void Pong::bounceBallSide()
519) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

520)   if (m_ballPosY <= 0 && m_ballDirY < 0) {
521)     m_ballDirY = 1;
522)   }
523)   if (m_ballPosY >= m_height - 1 && m_ballDirY > 0) {
524)     m_ballDirY = -1;
525)   }
526)   if (m_ballPosX <= 0 && m_ballDirX < 0) {
527)     m_ballDirX = 1;
528)   }
529)   if (m_ballPosX >= m_width - 1 && m_ballDirX > 0) {
530)     m_ballDirX = -1;
531)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

532) }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

534) /// bounce ball at left pad
535) void Pong::bounceBallLeft()
536) {
537)   if (m_ballPosX != 1 || m_ballDirX >= 0) {
538)     return;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

539)   }
540) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

541)   // top corner
542)   if (m_ballPosY == m_leftPosY - 1 && m_ballDirY > 0) {
543)     m_ballDirX = 1;
544)     m_ballDirY = -1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

546)   }
547) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

553)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

560)   }
561) }
562) 
563) /// bounce ball at right pad
564) void Pong::bounceBallRight()
565) {
566)   if (m_ballPosX != m_width - 2 || m_ballDirX <= 0) {
567)     return;
568)   }
569) 
570)   // top corner
571)   if (m_ballPosY == m_rightPosY - 1 && m_ballDirY > 0) {
572)     m_ballDirX = -1;
573)     m_ballDirY = -1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

575)   }
576) 
577)   // bottom corner
578)   else if (m_ballPosY == m_rightPosY + m_padSize && m_ballDirY < 0) {
579)     m_ballDirX = -1;
580)     m_ballDirY = 1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

582)   }
583) 
584)   // pad edge
585)   else if (m_ballPosY >= m_rightPosY &&
586)            m_ballPosY < m_rightPosY + m_padSize) {
587)     m_ballDirX = -1;
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

588)     ++m_bounceCnt;
589)   }
590) }
591) 
592) /// detect goal
593) void Pong::detectGoal()
594) {
595)   static int goalBlinkCnt = 3;
596)   static int goalDelay = goalBlinkCnt * 8 + 3;
597) 
598)   // ball at far left - goal for right player
599)   if (m_ballPosX == 0) {
600)     m_goalDelay = goalDelay;
601)     ++m_scoreRight;
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

602)     // play sound - score or win
603)     if (m_scoreRight >= (int)m_maxScore) {
604)       playOpConnSound(m_pConnRight, m_fileWinSound);
605)       playOpConnSound(m_pConnLeft, m_fileLoseSound);
606)     } else {
607)       playOpConnSound(m_pConnRight, m_fileScoreSound);
608)       playOpConnSound(m_pConnLeft, m_fileOtherScoreSound);
609)     }
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

610)   }
611) 
612)   // ball at far right - goal for left player
613)   else if (m_ballPosX == m_width - 1) {
614)     m_goalDelay = goalDelay;
615)     ++m_scoreLeft;
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

616)     // play sound - score or win
617)     if (m_scoreLeft >= (int)m_maxScore) {
618)       playOpConnSound(m_pConnLeft, m_fileWinSound);
619)       playOpConnSound(m_pConnRight, m_fileLoseSound);
620)     } else {
621)       playOpConnSound(m_pConnLeft, m_fileScoreSound);
622)       playOpConnSound(m_pConnRight, m_fileOtherScoreSound);
623)     }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

624)   }
625) }
626) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

633)     return;
634)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

635) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

640) 
641)   // request next time call
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

645) }
646) 
647) /// start ball
648) void Pong::startBall()
649) {
Stefan Schuermans pong: start ball at side

Stefan Schuermans authored 5 years ago

650)   // horizontal start direction opposite as before goal or random
651)   if (m_ballDirX > 0) {
652)     m_ballDirX = -1;
653)   } else if (m_ballDirX < 0) {
654)     m_ballDirX = 1;
655)   } else {
656)     m_ballDirX = (rand() & 1) * 2 - 1;
657)   }
658)   // random vertical start direction
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

661)   // horizontal start postion at side of field (depending on direction)
662)   m_ballPosX = m_ballDirX > 0 ? 0 : m_width - 1;
663)   // random vertical start position
664)   m_ballPosY = rand() % m_height;
665) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

666)   // no delays, ball has not bounced at pad
667)   m_leftDelay = 0;
668)   m_rightDelay = 0;
669)   m_goalDelay = 0;
670)   m_bounceCnt = 0;
671) 
672)   // draw and send frame
673)   redraw();
674) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

677) }
678) 
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

679) /// game over: close player connections and deactivate
680) void Pong::gameOver()
681) {
682)   // close open operator connections
683)   if (m_pConnLeft) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

685)     m_pConnLeft->close();
686)     m_pConnLeft = NULL;
687)   }
688)   if (m_pConnRight) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

690)     m_pConnRight->close();
691)     m_pConnRight = NULL;
692)   }
693) 
694)   // deactivate game
695)   deactivate();
696) }
697) 
Stefan Schuermans use same odering in source...

Stefan Schuermans authored 5 years ago

698) /// descriptor for delay value
699) Pong::ValueDescr const Pong::c_delayDescr = { 200, 100, 500 };
700) /// descriptor for maximum score value
701) Pong::ValueDescr const Pong::c_maxScoreDescr = { 9, 1, 99 };
702) 
703) /// operator connection name suffix for left player's connection
704) std::string const Pong::c_opConnSuffixLeft = "/left";
705) /// operator connection name suffix for right player's connection
706) std::string const Pong::c_opConnSuffixRight = "/right";
707)