75aef1e85a19adf55103091c9f6c04e79fb8d861
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),
38)   m_padSize(0), m_leftPosY(0), m_rightPosY(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 begin of Pong game

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

129) /**
130)  * @brief computation of ideal pad position for computer players
131)  * @param[in] padBallX x coordinate of position of ball when hitting the pad
132)  * @param[in] padY current y coordinate of pad
133)  * @param[out] padYmin minimum ideal y position of pad
134)  * @param[out] padYmax maximum ideal y position of pad
135)  */
136) void Pong::computerComputePadPos(int padBallX, int padY,
137)                                  int &padYmin, int &padYmax) const
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

138) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

139)   // ball not moving towards pad
140)   if ((padBallX - m_ballPosX) * m_ballDirX <= 0) {
141)     // do not move if ball is still close to pad
142)     if (abs(padBallX - m_ballPosX) <= 2) {
143)       padYmin = padY;
144)       padYmax = padY;
145)       return;
146)     }
147)     // move pad to middle (might be 2 pixels wide)
148)     padYmin = (m_height - m_padSize) / 2;
149)     padYmax = (m_height - m_padSize + 1) / 2;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

150)     return;
151)   }
152) 
153)   // compute expected ball position at pad
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

154)   int ballPosX = m_ballPosX; // simulate were ball is going
155)   int ballPosY = m_ballPosY;
156)   int ballDirY = m_ballDirY;
157)   while ((padBallX - ballPosX) * m_ballDirX > 0) { // while moving to pad
158)     int deltaX = padBallX - ballPosX;
159)     int deltaY = deltaX * m_ballDirX * ballDirY;
160)     if (deltaY < -ballPosY) {
161)       deltaY = -ballPosY;
162)       ballPosX += deltaY * m_ballDirX * ballDirY;
163)       ballPosY = 0;
164)       ballDirY = 1;
165)     }
166)     else if (deltaY > m_height - 1 - ballPosY) {
167)       deltaY = m_height - 1 - ballPosY;
168)       ballPosX += deltaY * m_ballDirX * ballDirY;
169)       ballPosY = m_height - 1;
170)       ballDirY = -1;
171)     } else {
172)       ballPosX += deltaX;
173)       ballPosY += deltaY;
174)     }
175)   }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

178)   padYmin = ballPosY - m_padSize / 2;
179)   padYmax = ballPosY - (m_padSize - 1) / 2;
180) }
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

181) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

182) /**
183)  * @brief move pad for computer players
184)  * @param[in] padYmin minimum desired y position of pad
185)  * @param[in] padYmax maximum desired y position of pad
186)  * @param[in,out] padPosY y position of pad
187)  */
188) void Pong::computerMovePad(int padYmin, int padYmax, int &padPosY) const
189) {
190)   // move pad, do not move pad out of field
191)   if (padPosY > padYmax && padPosY > 0) {
192)     --padPosY;
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

193)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

196)   }
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

198) 
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

199) /// computer player for left pad
200) void Pong::computerLeft()
201) {
202)   int padYmin, padYmax;
203)   computerComputePadPos(1, m_leftPosY, padYmin, padYmax);
204)   computerMovePad(padYmin, padYmax, m_leftPosY);
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

205) }
206) 
207) /// computer player for right pad
208) void Pong::computerRight()
209) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

210)   int padYmin, padYmax;
211)   computerComputePadPos(m_width - 2, m_rightPosY, padYmin, padYmax);
212)   computerMovePad(padYmin, padYmax, m_rightPosY);
Stefan Schuermans implement simple, fast comp...

Stefan Schuermans authored 5 years ago

213) }
214) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

215) /// bounce ball
216) void Pong::bounceBall()
217) {
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

219)   bounceBallLeft();
220)   bounceBallRight();
Stefan Schuermans pong: make computer perfect

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

222) }
223) 
224) /// bounce ball at sides
225) void Pong::bounceBallSide()
226) {
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

227)   if (m_ballPosY <= 0 && m_ballDirY < 0) {
228)     m_ballDirY = 1;
229)   }
230)   if (m_ballPosY >= m_height - 1 && m_ballDirY > 0) {
231)     m_ballDirY = -1;
232)   }
233)   if (m_ballPosX <= 0 && m_ballDirX < 0) {
234)     m_ballDirX = 1;
235)   }
236)   if (m_ballPosX >= m_width - 1 && m_ballDirX > 0) {
237)     m_ballDirX = -1;
238)   }
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

239) }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

241) /// bounce ball at left pad
242) void Pong::bounceBallLeft()
243) {
244)   if (m_ballPosX != 1 || m_ballDirX >= 0) {
245)     return;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

246)   }
247) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

248)   // top corner
249)   if (m_ballPosY == m_leftPosY - 1 && m_ballDirY > 0) {
250)     m_ballDirX = 1;
251)     m_ballDirY = -1;
Stefan Schuermans pong: add pads

Stefan Schuermans authored 5 years ago

252)   }
253) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

254)   // bottom corner
255)   else if (m_ballPosY == m_leftPosY + m_padSize && m_ballDirY < 0) {
256)     m_ballDirX = 1;
257)     m_ballDirY = 1;
258)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

260)   // pad edge
261)   else if (m_ballPosY >= m_leftPosY &&
262)            m_ballPosY < m_leftPosY + m_padSize) {
263)     m_ballDirX = 1;
264)   }
265) }
266) 
267) /// bounce ball at right pad
268) void Pong::bounceBallRight()
269) {
270)   if (m_ballPosX != m_width - 2 || m_ballDirX <= 0) {
271)     return;
272)   }
273) 
274)   // top corner
275)   if (m_ballPosY == m_rightPosY - 1 && m_ballDirY > 0) {
276)     m_ballDirX = -1;
277)     m_ballDirY = -1;
278)   }
279) 
280)   // bottom corner
281)   else if (m_ballPosY == m_rightPosY + m_padSize && m_ballDirY < 0) {
282)     m_ballDirX = -1;
283)     m_ballDirY = 1;
284)   }
285) 
286)   // pad edge
287)   else if (m_ballPosY >= m_rightPosY &&
288)            m_ballPosY < m_rightPosY + m_padSize) {
289)     m_ballDirX = -1;
290)   }
291) }
292) 
293) /// request next time call - or cancel request if not needed
294) void Pong::planTimeCall()
295) {
296)   if (m_ballPosX < 0 ||  m_ballPosY < 0) {
297)     m_mgrs.m_callMgr.cancelTimeCall(this);
298)     return;
299)   }
Stefan Schuermans pong: make ball move

Stefan Schuermans authored 5 years ago

300) 
301)   Time stepTime;
302)   stepTime.fromMs(100);
303)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + stepTime);
304) }
305) 
306) /// move ball out of the field and halt it
307) void Pong::hideBall()
308) {
309)   m_ballPosX = -1;
310)   m_ballPosY = -1;
311)   m_ballDirX = 0;
312)   m_ballDirY = 0;
313) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

316) }
317) 
318) /// start ball
319) void Pong::startBall()
320) {
321)   // ball starts horizontally at middle of field, vertically random
322)   m_ballPosX = (m_width - (rand() & 1)) / 2;
323)   m_ballPosY = rand() % m_height;
324)   // random diagonal direction
325)   m_ballDirX = (rand() & 1) * 2 - 1;
326)   m_ballDirY = (rand() & 1) * 2 - 1;
327) 
Stefan Schuermans pong: split large time func...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

330) }
331)