Stefan Schuermans commited on 2019-06-15 21:28:51
Showing 2 changed files, with 95 additions and 5 deletions.
| ... | ... |
@@ -3,6 +3,7 @@ |
| 3 | 3 |
Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html |
| 4 | 4 |
a blinkenarea.org project */ |
| 5 | 5 |
|
| 6 |
+#include <cmath> |
|
| 6 | 7 |
#include <stdlib.h> |
| 7 | 8 |
#include <string> |
| 8 | 9 |
#include <vector> |
| ... | ... |
@@ -43,9 +44,10 @@ Pong::Pong(const std::string &name, Mgrs &mgrs, const Directory &dirBase): |
| 43 | 44 |
m_filePadColor(dirBase.getFile("padColor")),
|
| 44 | 45 |
m_fileComputerColor(dirBase.getFile("computerColor")),
|
| 45 | 46 |
m_ballColor(), m_lineColor(), m_padColor(), m_computerColor(), |
| 47 |
+ m_pConnLeft(NULL), m_pConnRight(NULL), |
|
| 46 | 48 |
m_ballPosX(-1), m_ballPosY(-1), m_ballDirX(0), m_ballDirY(0), |
| 47 | 49 |
m_padSize(0), m_leftPosY(0), m_rightPosY(0), m_leftDelay(0), m_rightDelay(0), |
| 48 |
- m_pConnLeft(NULL), m_pConnRight(NULL) |
|
| 50 |
+ m_goalDelay(0), m_bounceCnt(0), m_scoreLeft(0), m_scoreRight(0) |
|
| 49 | 51 |
{
|
| 50 | 52 |
// open operator connection interfaces for left and right player |
| 51 | 53 |
m_mgrs.m_opMgr.open(m_name + OpConnSuffixLeft, this); |
| ... | ... |
@@ -226,8 +228,10 @@ void Pong::redraw() |
| 226 | 228 |
lineVert(m_rightPosY, m_rightPosY + m_padSize - 1, m_width - 1, |
| 227 | 229 |
m_pConnRight ? m_padColor : m_computerColor); |
| 228 | 230 |
|
| 229 |
- // draw ball |
|
| 231 |
+ // draw ball (blinking if goal delay is active) |
|
| 232 |
+ if (m_goalDelay <= 0 || (m_goalDelay & 4) == 0) {
|
|
| 230 | 233 |
pixel(m_ballPosY, m_ballPosX, m_ballColor); |
| 234 |
+ } |
|
| 231 | 235 |
|
| 232 | 236 |
// send updated image buffer as frame |
| 233 | 237 |
sendFrame(); |
| ... | ... |
@@ -236,6 +240,9 @@ void Pong::redraw() |
| 236 | 240 |
/// callback when requested time reached |
| 237 | 241 |
void Pong::timeCall() |
| 238 | 242 |
{
|
| 243 |
+ // game is running |
|
| 244 |
+ if (m_goalDelay <= 0 && m_ballPosX >= 0 && m_ballPosY >= 0) {
|
|
| 245 |
+ |
|
| 239 | 246 |
// computer player: move pads |
| 240 | 247 |
if (! m_pConnLeft) {
|
| 241 | 248 |
computerLeft(); |
| ... | ... |
@@ -251,6 +258,23 @@ void Pong::timeCall() |
| 251 | 258 |
m_ballPosX += m_ballDirX; |
| 252 | 259 |
m_ballPosY += m_ballDirY; |
| 253 | 260 |
|
| 261 |
+ // detect goal |
|
| 262 |
+ detectGoal(); |
|
| 263 |
+ |
|
| 264 |
+ } |
|
| 265 |
+ // goal delay (blinking ball) |
|
| 266 |
+ else if (m_goalDelay > 0) {
|
|
| 267 |
+ |
|
| 268 |
+ --m_goalDelay; |
|
| 269 |
+ |
|
| 270 |
+ // new ball when delay is over |
|
| 271 |
+ if (m_goalDelay <= 0) {
|
|
| 272 |
+ startBall(); |
|
| 273 |
+ return; // startBall calls redraw() and planTimeCall() |
|
| 274 |
+ } |
|
| 275 |
+ |
|
| 276 |
+ } |
|
| 277 |
+ |
|
| 254 | 278 |
// draw and send frame |
| 255 | 279 |
redraw(); |
| 256 | 280 |
|
| ... | ... |
@@ -265,6 +289,11 @@ void Pong::timeCall() |
| 265 | 289 |
*/ |
| 266 | 290 |
void Pong::processKey(char key, int &padPosY) |
| 267 | 291 |
{
|
| 292 |
+ // do not move pad if goal delay is active |
|
| 293 |
+ if (m_goalDelay > 0) {
|
|
| 294 |
+ return; |
|
| 295 |
+ } |
|
| 296 |
+ |
|
| 268 | 297 |
// move pad (2 = up, 8 = down), do not move pad out of field |
| 269 | 298 |
if (key == '2' && padPosY > 0) {
|
| 270 | 299 |
--padPosY; |
| ... | ... |
@@ -359,6 +388,11 @@ void Pong::computerComputePadPos(int padBallX, int padY, |
| 359 | 388 |
*/ |
| 360 | 389 |
void Pong::computerMovePad(int padYmin, int padYmax, int &padPosY) const |
| 361 | 390 |
{
|
| 391 |
+ // do not move pad if goal delay is active |
|
| 392 |
+ if (m_goalDelay > 0) {
|
|
| 393 |
+ return; |
|
| 394 |
+ } |
|
| 395 |
+ |
|
| 362 | 396 |
// move pad, do not move pad out of field |
| 363 | 397 |
if (padPosY > padYmax && padPosY > 0) {
|
| 364 | 398 |
--padPosY; |
| ... | ... |
@@ -425,18 +459,21 @@ void Pong::bounceBallLeft() |
| 425 | 459 |
if (m_ballPosY == m_leftPosY - 1 && m_ballDirY > 0) {
|
| 426 | 460 |
m_ballDirX = 1; |
| 427 | 461 |
m_ballDirY = -1; |
| 462 |
+ ++m_bounceCnt; |
|
| 428 | 463 |
} |
| 429 | 464 |
|
| 430 | 465 |
// bottom corner |
| 431 | 466 |
else if (m_ballPosY == m_leftPosY + m_padSize && m_ballDirY < 0) {
|
| 432 | 467 |
m_ballDirX = 1; |
| 433 | 468 |
m_ballDirY = 1; |
| 469 |
+ ++m_bounceCnt; |
|
| 434 | 470 |
} |
| 435 | 471 |
|
| 436 | 472 |
// pad edge |
| 437 | 473 |
else if (m_ballPosY >= m_leftPosY && |
| 438 | 474 |
m_ballPosY < m_leftPosY + m_padSize) {
|
| 439 | 475 |
m_ballDirX = 1; |
| 476 |
+ ++m_bounceCnt; |
|
| 440 | 477 |
} |
| 441 | 478 |
} |
| 442 | 479 |
|
| ... | ... |
@@ -451,31 +488,59 @@ void Pong::bounceBallRight() |
| 451 | 488 |
if (m_ballPosY == m_rightPosY - 1 && m_ballDirY > 0) {
|
| 452 | 489 |
m_ballDirX = -1; |
| 453 | 490 |
m_ballDirY = -1; |
| 491 |
+ ++m_bounceCnt; |
|
| 454 | 492 |
} |
| 455 | 493 |
|
| 456 | 494 |
// bottom corner |
| 457 | 495 |
else if (m_ballPosY == m_rightPosY + m_padSize && m_ballDirY < 0) {
|
| 458 | 496 |
m_ballDirX = -1; |
| 459 | 497 |
m_ballDirY = 1; |
| 498 |
+ ++m_bounceCnt; |
|
| 460 | 499 |
} |
| 461 | 500 |
|
| 462 | 501 |
// pad edge |
| 463 | 502 |
else if (m_ballPosY >= m_rightPosY && |
| 464 | 503 |
m_ballPosY < m_rightPosY + m_padSize) {
|
| 465 | 504 |
m_ballDirX = -1; |
| 505 |
+ ++m_bounceCnt; |
|
| 506 |
+ } |
|
| 507 |
+} |
|
| 508 |
+ |
|
| 509 |
+/// detect goal |
|
| 510 |
+void Pong::detectGoal() |
|
| 511 |
+{
|
|
| 512 |
+ static int goalBlinkCnt = 3; |
|
| 513 |
+ static int goalDelay = goalBlinkCnt * 8 + 3; |
|
| 514 |
+ |
|
| 515 |
+ // ball at far left - goal for right player |
|
| 516 |
+ if (m_ballPosX == 0) {
|
|
| 517 |
+ m_goalDelay = goalDelay; |
|
| 518 |
+ ++m_scoreRight; |
|
| 519 |
+ } |
|
| 520 |
+ |
|
| 521 |
+ // ball at far right - goal for left player |
|
| 522 |
+ else if (m_ballPosX == m_width - 1) {
|
|
| 523 |
+ m_goalDelay = goalDelay; |
|
| 524 |
+ ++m_scoreLeft; |
|
| 466 | 525 |
} |
| 467 | 526 |
} |
| 468 | 527 |
|
| 469 | 528 |
/// request next time call - or cancel request if not needed |
| 470 | 529 |
void Pong::planTimeCall() |
| 471 | 530 |
{
|
| 531 |
+ // no time call needed if game is not running |
|
| 472 | 532 |
if (m_ballPosX < 0 || m_ballPosY < 0) {
|
| 473 | 533 |
m_mgrs.m_callMgr.cancelTimeCall(this); |
| 474 | 534 |
return; |
| 475 | 535 |
} |
| 476 | 536 |
|
| 537 |
+ // compute interval based on score and bounce count |
|
| 538 |
+ float speedup = 10 * (m_scoreLeft + m_scoreRight) + m_bounceCnt; |
|
| 539 |
+ float interval = 0.05f + 0.1f * expf(-0.03f * speedup); |
|
| 540 |
+ |
|
| 541 |
+ // request next time call |
|
| 477 | 542 |
Time stepTime; |
| 478 |
- stepTime.fromMs(100); |
|
| 543 |
+ stepTime.fromFloatSec(interval); |
|
| 479 | 544 |
m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + stepTime); |
| 480 | 545 |
} |
| 481 | 546 |
|
| ... | ... |
@@ -487,6 +552,15 @@ void Pong::hideBall() |
| 487 | 552 |
m_ballDirX = 0; |
| 488 | 553 |
m_ballDirY = 0; |
| 489 | 554 |
|
| 555 |
+ // no delays, ball has not bounced at pad |
|
| 556 |
+ m_leftDelay = 0; |
|
| 557 |
+ m_rightDelay = 0; |
|
| 558 |
+ m_goalDelay = 0; |
|
| 559 |
+ m_bounceCnt = 0; |
|
| 560 |
+ |
|
| 561 |
+ // draw and send frame |
|
| 562 |
+ redraw(); |
|
| 563 |
+ |
|
| 490 | 564 |
// update time call request |
| 491 | 565 |
planTimeCall(); |
| 492 | 566 |
} |
| ... | ... |
@@ -501,6 +575,15 @@ void Pong::startBall() |
| 501 | 575 |
m_ballDirX = (rand() & 1) * 2 - 1; |
| 502 | 576 |
m_ballDirY = (rand() & 1) * 2 - 1; |
| 503 | 577 |
|
| 578 |
+ // no delays, ball has not bounced at pad |
|
| 579 |
+ m_leftDelay = 0; |
|
| 580 |
+ m_rightDelay = 0; |
|
| 581 |
+ m_goalDelay = 0; |
|
| 582 |
+ m_bounceCnt = 0; |
|
| 583 |
+ |
|
| 584 |
+ // draw and send frame |
|
| 585 |
+ redraw(); |
|
| 586 |
+ |
|
| 504 | 587 |
// request first time call if needed |
| 505 | 588 |
planTimeCall(); |
| 506 | 589 |
} |
| ... | ... |
@@ -152,6 +152,9 @@ protected: |
| 152 | 152 |
/// bounce ball at right pad |
| 153 | 153 |
void bounceBallRight(); |
| 154 | 154 |
|
| 155 |
+ /// detect goal |
|
| 156 |
+ void detectGoal(); |
|
| 157 |
+ |
|
| 155 | 158 |
/// request next time call - or cancel request if not needed |
| 156 | 159 |
void planTimeCall(); |
| 157 | 160 |
|
| ... | ... |
@@ -176,6 +179,8 @@ protected: |
| 176 | 179 |
ColorData m_lineColor; ///< center line color |
| 177 | 180 |
ColorData m_padColor; ///< phone player pad color |
| 178 | 181 |
ColorData m_computerColor; ///< computer player pad color |
| 182 |
+ OpConn *m_pConnLeft; ///< operator connection left player (or NULL) |
|
| 183 |
+ OpConn *m_pConnRight; ///< operator connection right player (o NULL) |
|
| 179 | 184 |
int m_ballPosX; ///< ball position X |
| 180 | 185 |
int m_ballPosY; ///< ball position Y |
| 181 | 186 |
int m_ballDirX; ///< ball direction X |
| ... | ... |
@@ -185,8 +190,10 @@ protected: |
| 185 | 190 |
int m_rightPosY; ///< position of top pixel of right pad |
| 186 | 191 |
int m_leftDelay; ///< delay for computer moving left pad |
| 187 | 192 |
int m_rightDelay; ///< delay for computer moving right pad |
| 188 |
- OpConn *m_pConnLeft; ///< operator connection left player (or NULL) |
|
| 189 |
- OpConn *m_pConnRight; ///< operator connection right player (o NULL) |
|
| 193 |
+ int m_goalDelay; ///< delay after goal (blinking ball) |
|
| 194 |
+ int m_bounceCnt; ///< how often the current ball bounced at pad |
|
| 195 |
+ int m_scoreLeft; ///< score of left player |
|
| 196 |
+ int m_scoreRight; ///< score of right player |
|
| 190 | 197 |
}; // class Canvas |
| 191 | 198 |
|
| 192 | 199 |
} // namespace Blinker |
| 193 | 200 |