ee4480a681f5610cc00f50bea914ed71e9796862
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: always check all configs

Stefan Schuermans authored 5 years ago

91)   if (colorUpdate(m_fileBallColor, m_ballColor)) { ret = true; }
92)   if (colorUpdate(m_fileLineColor, m_lineColor)) { ret = true; }
93)   if (colorUpdate(m_filePadColor, m_padColor)) { ret = true; }
94)   if (colorUpdate(m_fileComputerColor, m_computerColor)) { ret = true; }
95)   if (colorUpdate(m_fileScoreColor, m_scoreColor)) { ret = true; }
96)   if (colorUpdate(m_fileGoalColor, m_goalColor)) { ret = true; }
97)   if (valueUpdate(m_fileDelay, c_delayDescr, m_delay)) { ret = true; }
98)   if (valueUpdate(m_fileMaxScore, c_maxScoreDescr, m_maxScore)) { ret = true; }
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

99) 
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

108)   return ret;
109) }
110) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

111) /**
Stefan Schuermans fix comment typo

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

148)   }
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

150)   else {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

152)     return;
153)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

230)   }
231)   // nothing happens
232)   else {
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

233)     return;
234)   }
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

244) }
245) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

253)   m_leftDelay = 0;
254)   m_rightDelay = 0;
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

261)   color2data(m_fileScoreColor, m_scoreColor);
262)   color2data(m_fileGoalColor, m_goalColor);
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

302) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

303)   // draw ball (blinking if goal delay is active)
304)   if (m_goalDelay <= 0 || (m_goalDelay & 4) == 0) {
Stefan Schuermans fix indentation

Stefan Schuermans authored 5 years ago

305)     pixel(m_ballPosY, m_ballPosX, m_ballColor);
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

306)   }
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

339) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

355)     }
356) 
357)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

364) }
365) 
Stefan Schuermans pong: implement phone players

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

420) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

463) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

480)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

483)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

484) }
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) /// computer player for left pad
487) void Pong::computerLeft()
488) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

510)   bounceBallLeft();
511)   bounceBallRight();
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

530) }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

537)   }
538) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

544)   }
545) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

551)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

622)   }
623) }
624) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

631)     return;
632)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

633) 
Stefan Schuermans pong: goals, score, speedup

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

638) 
639)   // request next time call
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

675) }
676) 
Stefan Schuermans pong: end game when max sco...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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