e496ba31b360e9b71eff92f9b2933ed5f20299e4
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: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

7) #include <string>
8) #include <vector>
9) 
10) #include <BlinkenLib/BlinkenFrame.h>
11) 
12) #include "File.h"
13) #include "Format.h"
14) #include "FormatFile.h"
15) #include "Game.h"
16) #include "Mgrs.h"
17) #include "Module.h"
18) #include "OutStreamFile.h"
19) #include "Pong.h"
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

20) #include "Time.h"
21) #include "TimeCallee.h"
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

35)   m_filePadColor(dirBase.getFile("padColor")),
36)   m_ballColor(), m_lineColor(), m_padColor(),
37)   m_ballPosX(-1), m_ballPosY(-1), m_ballDirX(0), m_ballDirY(0),
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

38)   m_padSize(0), m_leftPosY(0), m_rightPosY(0), m_leftDelay(0), m_rightDelay(0)
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

39) {
40)   // FIXME: activate at begin for initial development only
41)   activate();
42) }
43) 
44) /// virtual destructor
45) Pong::~Pong()
46) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

49) }
50) 
51) /// check for update of configuration (derived game), return true on update
52) bool Pong::updateConfigGame()
53) {
54)   bool ret = false;
55) 
56)   // color file was modified -> convert color, return true for update
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

58)       colorUpdate(m_fileLineColor, m_lineColor) ||
59)       colorUpdate(m_filePadColor, m_padColor)) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

60)     ret = true;
61)   }
62) 
63)   return ret;
64) }
65) 
66) /// re-initialize game (e.g. due to config change)
67) void Pong::reinitialize()
68) {
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

69)   // compute parameters
70)   m_padSize = (m_height + 1) / 3;
71)   m_leftPosY = (m_height - m_padSize) / 2;
72)   m_rightPosY = (m_height - m_padSize) / 2;
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

73)   m_leftDelay = 0;
74)   m_rightDelay = 0;
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

75) 
76)   // convert colors
77)   color2data(m_fileBallColor, m_ballColor);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

79)   color2data(m_filePadColor, m_padColor);
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

80) 
81)   // FIXME: start ball for development
82)   startBall();
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

83) }
84) 
85) /// redraw current game image, expected to call sendFrame() at end
86) void Pong::redraw()
87) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

88)   int y, x;
89) 
90)   // draw background
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

93)   // draw middle line: single line on odd width, two dashed lines at even width
94)   for (y = 0; y < m_height; ++y) {
95)     x = (m_width - (y & 1)) / 2;
96)     pixel(y, x, m_lineColor);
97)   }
98) 
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

99)   // draw pads
100)   lineVert(m_leftPosY, m_leftPosY + m_padSize - 1, 0, m_padColor);
101)   lineVert(m_rightPosY, m_rightPosY + m_padSize - 1, m_width - 1, m_padColor);
102) 
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

103)   // draw ball
104)   pixel(m_ballPosY, m_ballPosX, m_ballColor);
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

105) 
106)   // send updated image buffer as frame
107)   sendFrame();
108) }
109) 
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

110) /// callback when requested time reached
111) void Pong::timeCall()
112) {
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

113)   // computer player: move pads
114)   computerLeft();
115)   computerRight();
116) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

117)   // bounce ball
118)   bounceBall();
119) 
120)   // move ball
121)   m_ballPosX += m_ballDirX;
122)   m_ballPosY += m_ballDirY;
123) 
124)   // draw and send frame
125)   redraw();
126) 
127)   // request next call if needed
128)   planTimeCall();
129) }
130) 
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

131) /**
132)  * @brief delay processing for computer players
133)  * @param[in,out] delay delay variable of computer player
134)  * @return whether computer player is allowed to move
135)  */
136) bool Pong::computerDelay(int &delay) const
137) 
138) {
139)   // zero delay: generate new delay
140)   if (delay <= 0) {
141)     int avg_steps = (m_height - m_padSize) / 2;
142)     int delay_range = avg_steps > 1 ? m_width / avg_steps: m_width;
143)     delay = rand() % delay_range + delay_range;
144)   }
145) 
146)   // count down delay
147)   --delay;
148) 
149)   // moving allowd if delay expired
150)   return delay <= 0;
151) }
152) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

153) /**
154)  * @brief computation of ideal pad position for computer players
155)  * @param[in] padBallX x coordinate of position of ball when hitting the pad
156)  * @param[in] padY current y coordinate of pad
157)  * @param[out] padYmin minimum ideal y position of pad
158)  * @param[out] padYmax maximum ideal y position of pad
159)  */
160) void Pong::computerComputePadPos(int padBallX, int padY,
161)                                  int &padYmin, int &padYmax) const
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

162) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

163)   // ball not moving towards pad
164)   if ((padBallX - m_ballPosX) * m_ballDirX <= 0) {
165)     // do not move if ball is still close to pad
166)     if (abs(padBallX - m_ballPosX) <= 2) {
167)       padYmin = padY;
168)       padYmax = padY;
169)       return;
170)     }
171)     // move pad to middle (might be 2 pixels wide)
172)     padYmin = (m_height - m_padSize) / 2;
173)     padYmax = (m_height - m_padSize + 1) / 2;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

174)     return;
175)   }
176) 
177)   // compute expected ball position at pad
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

178)   int ballPosX = m_ballPosX; // simulate were ball is going
179)   int ballPosY = m_ballPosY;
180)   int ballDirY = m_ballDirY;
181)   while ((padBallX - ballPosX) * m_ballDirX > 0) { // while moving to pad
182)     int deltaX = padBallX - ballPosX;
183)     int deltaY = deltaX * m_ballDirX * ballDirY;
184)     if (deltaY < -ballPosY) {
185)       deltaY = -ballPosY;
186)       ballPosX += deltaY * m_ballDirX * ballDirY;
187)       ballPosY = 0;
188)       ballDirY = 1;
189)     }
190)     else if (deltaY > m_height - 1 - ballPosY) {
191)       deltaY = m_height - 1 - ballPosY;
192)       ballPosX += deltaY * m_ballDirX * ballDirY;
193)       ballPosY = m_height - 1;
194)       ballDirY = -1;
195)     } else {
196)       ballPosX += deltaX;
197)       ballPosY += deltaY;
198)     }
199)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

202)   padYmin = ballPosY - m_padSize / 2;
203)   padYmax = ballPosY - (m_padSize - 1) / 2;
204) }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

205) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

206) /**
207)  * @brief move pad for computer players
208)  * @param[in] padYmin minimum desired y position of pad
209)  * @param[in] padYmax maximum desired y position of pad
210)  * @param[in,out] padPosY y position of pad
211)  */
212) void Pong::computerMovePad(int padYmin, int padYmax, int &padPosY) const
213) {
214)   // move pad, do not move pad out of field
215)   if (padPosY > padYmax && padPosY > 0) {
216)     --padPosY;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

217)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

220)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

222) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

223) /// computer player for left pad
224) void Pong::computerLeft()
225) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

226)   if (computerDelay(m_leftDelay)) {
227)     int padYmin, padYmax;
228)     computerComputePadPos(1, m_leftPosY, padYmin, padYmax);
229)     computerMovePad(padYmin, padYmax, m_leftPosY);
230)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

231) }
232) 
233) /// computer player for right pad
234) void Pong::computerRight()
235) {
Stefan Schuermans pong: make computer slow

Stefan Schuermans authored 5 years ago

236)   if (computerDelay(m_rightDelay)) {
237)     int padYmin, padYmax;
238)     computerComputePadPos(m_width - 2, m_rightPosY, padYmin, padYmax);
239)     computerMovePad(padYmin, padYmax, m_rightPosY);
240)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

241) }
242) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

243) /// bounce ball
244) void Pong::bounceBall()
245) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

247)   bounceBallLeft();
248)   bounceBallRight();
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

250) }
251) 
252) /// bounce ball at sides
253) void Pong::bounceBallSide()
254) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

255)   if (m_ballPosY <= 0 && m_ballDirY < 0) {
256)     m_ballDirY = 1;
257)   }
258)   if (m_ballPosY >= m_height - 1 && m_ballDirY > 0) {
259)     m_ballDirY = -1;
260)   }
261)   if (m_ballPosX <= 0 && m_ballDirX < 0) {
262)     m_ballDirX = 1;
263)   }
264)   if (m_ballPosX >= m_width - 1 && m_ballDirX > 0) {
265)     m_ballDirX = -1;
266)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

267) }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

269) /// bounce ball at left pad
270) void Pong::bounceBallLeft()
271) {
272)   if (m_ballPosX != 1 || m_ballDirX >= 0) {
273)     return;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

274)   }
275) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

276)   // top corner
277)   if (m_ballPosY == m_leftPosY - 1 && m_ballDirY > 0) {
278)     m_ballDirX = 1;
279)     m_ballDirY = -1;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

280)   }
281) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

282)   // bottom corner
283)   else if (m_ballPosY == m_leftPosY + m_padSize && m_ballDirY < 0) {
284)     m_ballDirX = 1;
285)     m_ballDirY = 1;
286)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

288)   // pad edge
289)   else if (m_ballPosY >= m_leftPosY &&
290)            m_ballPosY < m_leftPosY + m_padSize) {
291)     m_ballDirX = 1;
292)   }
293) }
294) 
295) /// bounce ball at right pad
296) void Pong::bounceBallRight()
297) {
298)   if (m_ballPosX != m_width - 2 || m_ballDirX <= 0) {
299)     return;
300)   }
301) 
302)   // top corner
303)   if (m_ballPosY == m_rightPosY - 1 && m_ballDirY > 0) {
304)     m_ballDirX = -1;
305)     m_ballDirY = -1;
306)   }
307) 
308)   // bottom corner
309)   else if (m_ballPosY == m_rightPosY + m_padSize && m_ballDirY < 0) {
310)     m_ballDirX = -1;
311)     m_ballDirY = 1;
312)   }
313) 
314)   // pad edge
315)   else if (m_ballPosY >= m_rightPosY &&
316)            m_ballPosY < m_rightPosY + m_padSize) {
317)     m_ballDirX = -1;
318)   }
319) }
320) 
321) /// request next time call - or cancel request if not needed
322) void Pong::planTimeCall()
323) {
324)   if (m_ballPosX < 0 ||  m_ballPosY < 0) {
325)     m_mgrs.m_callMgr.cancelTimeCall(this);
326)     return;
327)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

328) 
329)   Time stepTime;
330)   stepTime.fromMs(100);
331)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + stepTime);
332) }
333) 
334) /// move ball out of the field and halt it
335) void Pong::hideBall()
336) {
337)   m_ballPosX = -1;
338)   m_ballPosY = -1;
339)   m_ballDirX = 0;
340)   m_ballDirY = 0;
341) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

342)   // update time call request
343)   planTimeCall();
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

344) }
345) 
346) /// start ball
347) void Pong::startBall()
348) {
349)   // ball starts horizontally at middle of field, vertically random
350)   m_ballPosX = (m_width - (rand() & 1)) / 2;
351)   m_ballPosY = rand() % m_height;
352)   // random diagonal direction
353)   m_ballDirX = (rand() & 1) * 2 - 1;
354)   m_ballDirY = (rand() & 1) * 2 - 1;
355) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

358) }
359)