RGBMatrixDisplay/src/mode/Pong/Pong.h

151 lines
4.0 KiB
C++

#ifndef PONG_H
#define PONG_H
#include "mode/Mode.h"
#include "Player.h"
#include "display/Vector.h"
class Pong : public Mode<Pong> {
private:
enum Status {
SCORE, PLAY, OVER
};
Player player0;
Player player1;
Vector position;
Vector velocity;
Status status = PLAY;
microseconds_t timeout = 0;
void resetPlayer() {
player0.size = 3;
player0.score = 0;
player0.position = (display->height - player0.size) / 2;
player1.size = 3;
player1.score = 0;
player1.position = (display->height - player1.size) / 2;
}
void tick(Timer *timer, uint32_t totalCount, uint32_t currentCount) {
switch (status) {
case SCORE:
timeout -= currentCount * timer->interval;
if (timeout <= 0) {
status = PLAY;
}
break;
case PLAY:
position.add(velocity);
player0.randomMove(display->height);
player1.randomMove(display->height);
paddleBounce();
checkScoring();
topBottomBounce();
draw();
break;
case OVER:
timeout -= currentCount * timer->interval;
if (timeout <= 0) {
resetPlayer();
status = SCORE;
timeout = 2000000;
}
break;
}
}
void topBottomBounce() {
position.bounceInBox(display->width, display->height);
}
void checkScoring() {
if (position.x < 0) {
player1.score++;
spawnBall(+1);
} else if (position.x >= display->width) {
player0.score++;
spawnBall(-1);
}
if (player0.score >= 10 || player1.score >= 10) {
status = OVER;
timeout = 2000000;
}
}
void paddleBounce() {
if (position.x == 1 && player0.position <= position.y && position.y < player0.position + player0.size) {
velocity.x = -velocity.x;
position.x = 3;
} else if (position.x == display->width - 2 && player1.position <= position.y && position.y < player1.position + player1.size) {
velocity.x = -velocity.x;
position.x = display->width - 4;
}
}
void spawnBall(int direction) {
position.x = (double) display->width / 2.0;
position.y = (double) display->height / 2.0;
velocity.x = direction;
velocity.y = 0;
status = SCORE;
timeout = 2000000;
}
void draw() {
display->clear();
switch (status) {
case SCORE:
display->print(1, 1, player0.score, 0, 255, 0);
display->print(display->width - 1 - DISPLAY_CHAR_WIDTH, 1, player1.score, 255, 0, 0);
break;
case PLAY:
for (int i = 0; i < player0.size; ++i) {
display->set(1, (uint8_t) round(player0.position) + i, 0, 255, 0);
}
for (int i = 0; i < player1.size; ++i) {
display->set(display->width - 2, (uint8_t) round(player1.position) + i, 255, 0, 0);
}
display->set((uint8_t) round(position.x), (uint8_t) round(position.y), 255, 255, 255);
break;
case OVER:
if (player0.score > player1.score) {
display->print(1, 1, 11, 0, 255, 0);
display->print(display->width - 1 - DISPLAY_CHAR_WIDTH, 1, 12, 255, 0, 0);
} else if (player0.score < player1.score) {
display->print(1, 1, 12, 255, 0, 0);
display->print(display->width - 1 - DISPLAY_CHAR_WIDTH, 1, 11, 0, 255, 0);
}
break;
}
}
public:
explicit Pong(Display *display) :
Mode(display),
position(display->width / 2.0, display->height / 2.0),
velocity(random(360), exp10(1)) {
instance = this;
createTimer(100, [](Timer *timer, uint32_t counter, uint32_t currentCount) { instance->tick(timer, counter, currentCount); });
spawnBall(random(2) == 0 ? -1 : +1);
resetPlayer();
}
~Pong() override = default;
const char *getName() override {
return "Pong";
}
};
#endif