f857cc5b5586b1563e9681eac068534df6341b53
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)   }
85) 
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

86)   // cancel time callback request
87)   m_mgrs.m_callMgr.cancelTimeCall(this);
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

99)       colorUpdate(m_fileComputerColor, m_computerColor) ||
100)       colorUpdate(m_fileScoreColor, m_scoreColor) ||
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

104)     ret = true;
105)   }
106) 
107)   return ret;
108) }
109) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

110) /**
Stefan Schuermans fix comment typo

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

119)     return true;
120)   }
121)   // right player can join if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

140)     m_pConnLeft = pConn;
141)   }
142)   // right player joins if none there yet
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

145)   }
146)   // nothing happens
147)   else {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

148)     return;
149)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

174)     processKey(key, m_rightPosY);
175)   }
176) }
177) 
178) /**
179)  * @brief play command received on operator connection
180)  * @param[in] pConn operator connection object
181)  * @param[in] sound name of sound to play
182)  */
183) void Pong::opConnRecvPlay(OpConn *pConn, const std::string &sound)
184) {
185)   (void)pConn;
186)   (void)sound;
187) }
188) 
189) /**
190)  * @brief operator connection is closed
191)  * @param[in] pConn operator connection object
192)  *
193)  * The connection may not be used for sending any more in this callback.
194)  */
195) void Pong::opConnClose(OpConn *pConn)
196) {
197)   // left player leaves
198)   if (pConn == m_pConnLeft) {
199)     m_pConnLeft = NULL;
200)   }
201)   // right player leaves
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

218) }
219) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

276) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

281) 
282)   // send updated image buffer as frame
283)   sendFrame();
284) }
285) 
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

286) /// callback when requested time reached
287) void Pong::timeCall()
288) {
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

313) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

318)         // maximum score reached
319)         if (m_scoreLeft >= (int)m_maxScore ||
320)             m_scoreRight >= (int)m_maxScore) {
321)           gameOver();
322)           return; // no gameOver() calls deactivate(), no need to redraw
323)         }
324)         // game continues with new ball
325)         else {
326)           startBall();
327)           return; // startBall() calls redraw() and planTimeCall()
328)         }
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

332) 
333)   // draw and send frame
334)   redraw();
335) 
336)   // request next call if needed
337)   planTimeCall();
338) }
339) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

394) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

437) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

454)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

457)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

459) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

504) }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

525)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

580)   }
581) }
582) 
583) /// request next time call - or cancel request if not needed
584) void Pong::planTimeCall()
585) {
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

586)   // no time call needed if not active
587)   if (! isActive()) {
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

588)     m_mgrs.m_callMgr.cancelTimeCall(this);
589)     return;
590)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

591) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

599)   stepTime.fromFloatSec(interval);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

600)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + stepTime);
601) }
602) 
603) /// start ball
604) void Pong::startBall()
605) {
Stefan Schuermans pong: start ball at side

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

622)   // no delays, ball has not bounced at pad
623)   m_leftDelay = 0;
624)   m_rightDelay = 0;
625)   m_goalDelay = 0;
626)   m_bounceCnt = 0;
627) 
628)   // draw and send frame
629)   redraw();
630) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

631)   // request first time call if needed
632)   planTimeCall();
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

635) 
636) /// game over: close player connections and deactivate
637) void Pong::gameOver()
638) {
639)   // close open operator connections
640)   if (m_pConnLeft) {
641)     m_pConnLeft->close();
642)     m_pConnLeft = NULL;
643)   }
644)   if (m_pConnRight) {
645)     m_pConnRight->close();
646)     m_pConnRight = NULL;
647)   }
648) 
649)   // deactivate game
650)   deactivate();
651) }
652)