Pong
This commit is contained in:
parent
4030b9136a
commit
72e5946a0e
@ -30,4 +30,4 @@ add_custom_target(
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_executable(Z_DUMMY_TARGET ${SRC_LIST} src/mode/Test/Border.h src/mode/Clock/Clock.h src/mode/SpaceInvaders/SpaceInvaders.h)
|
||||
add_executable(Z_DUMMY_TARGET ${SRC_LIST} src/mode/Test/Border.h src/mode/Clock/Clock.h src/mode/SpaceInvaders/SpaceInvaders.h src/mode/Timer.h src/mode/Pong/Pong.cpp src/BASICS.cpp src/display/Display.cpp)
|
||||
|
||||
@ -13,7 +13,9 @@ platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
lib_deps = https://github.com/adafruit/Adafruit_NeoPixel
|
||||
upload_port = /dev/ttyUSB0
|
||||
upload_speed = 921600
|
||||
upload_port = 10.0.0.120
|
||||
upload_protocol = espota
|
||||
;upload_port = /dev/ttyUSB0
|
||||
;upload_speed = 921600
|
||||
monitor_port = /dev/ttyUSB0
|
||||
monitor_speed = 115200
|
||||
|
||||
23
src/BASICS.cpp
Normal file
23
src/BASICS.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "BASICS.h"
|
||||
|
||||
double step(double valueCurrent, double valueMin, double valueMax, microseconds_t timeTotal, microseconds_t timeDelta) {
|
||||
double valueRange = valueMax - valueMin;
|
||||
double timeRatio = (double) timeDelta / (double) timeTotal;
|
||||
double valueStep = valueRange * timeRatio;
|
||||
double valueNew = max(valueMin, min(valueMax, valueCurrent + valueStep));
|
||||
// Serial.printf("valueCurrent: %13.3f\n", valueCurrent);
|
||||
// Serial.printf("valueMin: %13.3f\n", valueMin);
|
||||
// Serial.printf("valueMax: %13.3f\n", valueMax);
|
||||
// Serial.printf("valueRange: %13.3f\n", valueRange);
|
||||
// Serial.printf("timeTotal: %13.3f\n", (double) timeTotal);
|
||||
// Serial.printf("timeDelta: %13.3f\n", (double) timeDelta);
|
||||
// Serial.printf("timeRatio: %13.3f\n", timeRatio);
|
||||
// Serial.printf("valueStep: %13.3f\n", valueStep);
|
||||
// Serial.printf("valueNew: %13.3f\n", valueNew);
|
||||
// Serial.println();
|
||||
return valueNew;
|
||||
}
|
||||
|
||||
bool randomBool(int uncertainty) {
|
||||
return random(uncertainty) == 0;
|
||||
}
|
||||
22
src/BASICS.h
22
src/BASICS.h
@ -8,26 +8,8 @@
|
||||
|
||||
typedef int64_t microseconds_t;
|
||||
|
||||
double step(double valueCurrent, double valueMin, double valueMax, microseconds_t timeTotal, microseconds_t timeDelta) {
|
||||
double valueRange = valueMax - valueMin;
|
||||
double timeRatio = (double) timeDelta / (double) timeTotal;
|
||||
double valueStep = valueRange * timeRatio;
|
||||
double valueNew = max(valueMin, min(valueMax, valueCurrent + valueStep));
|
||||
// Serial.printf("valueCurrent: %13.3f\n", valueCurrent);
|
||||
// Serial.printf("valueMin: %13.3f\n", valueMin);
|
||||
// Serial.printf("valueMax: %13.3f\n", valueMax);
|
||||
// Serial.printf("valueRange: %13.3f\n", valueRange);
|
||||
// Serial.printf("timeTotal: %13.3f\n", (double) timeTotal);
|
||||
// Serial.printf("timeDelta: %13.3f\n", (double) timeDelta);
|
||||
// Serial.printf("timeRatio: %13.3f\n", timeRatio);
|
||||
// Serial.printf("valueStep: %13.3f\n", valueStep);
|
||||
// Serial.printf("valueNew: %13.3f\n", valueNew);
|
||||
// Serial.println();
|
||||
return valueNew;
|
||||
}
|
||||
double step(double valueCurrent, double valueMin, double valueMax, microseconds_t timeTotal, microseconds_t timeDelta);
|
||||
|
||||
bool randomBool(int uncertainty) {
|
||||
return random(uncertainty) == 0;
|
||||
}
|
||||
bool randomBool(int uncertainty);
|
||||
|
||||
#endif
|
||||
|
||||
95
src/display/Display.cpp
Normal file
95
src/display/Display.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "Display.h"
|
||||
|
||||
bool SYMBOLS[SYMBOL_COUNT][DISPLAY_CHAR_WIDTH * DISPLAY_CHAR_HEIGHT] = {
|
||||
{
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, _, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
_, _, X,
|
||||
_, X, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
X, _, _,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
_, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, _, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, _,
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, _,
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
_, X, _,
|
||||
X, _, _,
|
||||
X, _, _,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
_, _, _,
|
||||
_, X, _,
|
||||
_, _, _,
|
||||
_, X, _,
|
||||
_, _, _,
|
||||
},
|
||||
{
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
X, _, X,
|
||||
_, X, _,
|
||||
},
|
||||
{
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
_, X, _,
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
},
|
||||
};
|
||||
@ -4,6 +4,12 @@
|
||||
#include "Pixel.h"
|
||||
#include "Adafruit_NeoPixel.h"
|
||||
|
||||
#define SYMBOL_COUNT 13
|
||||
#define DISPLAY_CHAR_WIDTH 3
|
||||
#define DISPLAY_CHAR_HEIGHT 5
|
||||
|
||||
extern bool SYMBOLS[SYMBOL_COUNT][DISPLAY_CHAR_WIDTH * DISPLAY_CHAR_HEIGHT];
|
||||
|
||||
class Display {
|
||||
|
||||
public:
|
||||
@ -33,6 +39,36 @@ public:
|
||||
clear();
|
||||
}
|
||||
|
||||
void print(uint8_t xPos, uint8_t yPos, uint8_t index, uint8_t r, uint8_t g, uint8_t b) {
|
||||
print(&xPos, yPos, index, r, g, b);
|
||||
}
|
||||
|
||||
void print(uint8_t xPos, uint8_t yPos, uint8_t index) {
|
||||
print(&xPos, yPos, index, 255, 255, 255);
|
||||
}
|
||||
|
||||
void print(uint8_t *xPos, uint8_t yPos, uint8_t index) {
|
||||
print(xPos, yPos, index, 255, 255, 255);
|
||||
}
|
||||
|
||||
void print(uint8_t *xPos, uint8_t yPos, uint8_t index, uint8_t r, uint8_t g, uint8_t b) {
|
||||
if (index >= SYMBOL_COUNT) {
|
||||
Serial.printf("Cannot print symbol #%u.\n", index);
|
||||
return;
|
||||
}
|
||||
bool *symbolBit = SYMBOLS[index];
|
||||
for (uint8_t y = 0; y < DISPLAY_CHAR_HEIGHT; ++y) {
|
||||
for (uint8_t x = 0; x < DISPLAY_CHAR_WIDTH; ++x) {
|
||||
if (*(symbolBit++)) {
|
||||
set(*xPos + x, yPos + y, r, g, b);
|
||||
} else {
|
||||
set(*xPos + x, yPos + y, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
*xPos += 3;
|
||||
}
|
||||
|
||||
void set(uint8_t x, uint8_t y, uint32_t color) {
|
||||
setPixelColor(x, y, color);
|
||||
}
|
||||
@ -67,6 +103,10 @@ public:
|
||||
return leds.getBrightness();
|
||||
}
|
||||
|
||||
void setIndex(uint16_t index, uint8_t r, uint8_t g, uint8_t b) {
|
||||
leds.setPixelColor(index, r, g, b);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -22,6 +22,30 @@ public:
|
||||
y = sin(radians) * length;
|
||||
}
|
||||
|
||||
Vector *add(Vector that) {
|
||||
this->x += that.x;
|
||||
this->y += that.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
Vector *bounceInBox(uint8_t width, uint8_t height) {
|
||||
while (x < 0 || x >= width) {
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
} else if (x >= width) {
|
||||
x = 2 * width - x;
|
||||
}
|
||||
}
|
||||
while (y < 0 || y >= height) {
|
||||
if (y < 0) {
|
||||
y = -y;
|
||||
} else if (y >= height) {
|
||||
y = 2 * height - y;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
24
src/main.cpp
24
src/main.cpp
@ -22,7 +22,7 @@ enum ModeId {
|
||||
|
||||
Display display(32, 8);
|
||||
|
||||
ModeId newModeId = SPACE_INVADERS;
|
||||
ModeId newModeId = PONG;
|
||||
|
||||
ModeId currentModeId = NONE;
|
||||
|
||||
@ -30,7 +30,7 @@ microseconds_t lastMicros = 0;
|
||||
|
||||
Mode *mode = nullptr;
|
||||
|
||||
double speed = 4.0;
|
||||
double speed = 1.0;
|
||||
|
||||
bool connected = false;
|
||||
|
||||
@ -49,6 +49,26 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("\n\n\nStartup!");
|
||||
WiFi.begin("HappyNet", "1Grausame!Sackratte7");
|
||||
ArduinoOTA.onStart([]() {
|
||||
display.clear();
|
||||
display.loop();
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int total, unsigned int progress) {
|
||||
double ratio = (double) progress / (double) total;
|
||||
auto index = (uint16_t) round(ratio * (double) display.pixelCount);
|
||||
auto color = (uint8_t) round(ratio * 255.0);
|
||||
display.setIndex(index, 255 - color, color, 0);
|
||||
display.loop();
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
display.clear();
|
||||
display.loop();
|
||||
});
|
||||
ArduinoOTA.onError([](int error) {
|
||||
display.clear();
|
||||
display.loop();
|
||||
});
|
||||
|
||||
ArduinoOTA.begin();
|
||||
display.setup();
|
||||
}
|
||||
|
||||
@ -5,88 +5,6 @@
|
||||
|
||||
class Clock : public Mode {
|
||||
|
||||
private:
|
||||
|
||||
bool SYMBOLS[11][35] = {
|
||||
{
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, _, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
_, _, X,
|
||||
_, X, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
X, _, _,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
_, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, _, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
_, _, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, _,
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, _,
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
_, X, _,
|
||||
X, _, _,
|
||||
X, _, _,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
X, X, X,
|
||||
X, _, X,
|
||||
X, X, X,
|
||||
_, _, X,
|
||||
X, X, X,
|
||||
},
|
||||
{
|
||||
_, _, _,
|
||||
_, X, _,
|
||||
_, _, _,
|
||||
_, X, _,
|
||||
_, _, _,
|
||||
},
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
explicit Clock(Display *display) :
|
||||
@ -100,37 +18,22 @@ public:
|
||||
return "Clock";
|
||||
}
|
||||
|
||||
void step(microseconds_t dt) override {
|
||||
void doStep(microseconds_t dt) override {
|
||||
tm time{};
|
||||
getLocalTime(&time);
|
||||
display->clear();
|
||||
uint8_t x = 0;
|
||||
print(&x, time.tm_hour / 10);
|
||||
display->print(&x, 1, time.tm_hour / 10);
|
||||
x++;
|
||||
print(&x, time.tm_hour % 10);
|
||||
print(&x, 10);
|
||||
print(&x, time.tm_min / 10);
|
||||
display->print(&x, 1, time.tm_hour % 10);
|
||||
display->print(&x, 1, 10);
|
||||
display->print(&x, 1, time.tm_min / 10);
|
||||
x++;
|
||||
print(&x, time.tm_min % 10);
|
||||
print(&x, 10);
|
||||
print(&x, time.tm_sec / 10);
|
||||
display->print(&x, 1, time.tm_min % 10);
|
||||
display->print(&x, 1, 10);
|
||||
display->print(&x, 1, time.tm_sec / 10);
|
||||
x++;
|
||||
print(&x, time.tm_sec % 10);
|
||||
}
|
||||
|
||||
void print(uint8_t *pos, uint8_t index) {
|
||||
if (index > 10) {
|
||||
Serial.printf("Cannot print symbol #%u.", index);
|
||||
return;
|
||||
}
|
||||
bool *symbolBit = SYMBOLS[index];
|
||||
for (uint8_t y = 0; y < 5; ++y) {
|
||||
for (uint8_t x = 0; x < 3; ++x) {
|
||||
uint8_t value = *(symbolBit++) ? 255 : 0;
|
||||
display->set(*pos + x, y, value, value, value);
|
||||
}
|
||||
}
|
||||
*pos += 3;
|
||||
display->print(&x, 1, time.tm_sec % 10);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ public:
|
||||
uint32_t color = 0;
|
||||
|
||||
void animate(microseconds_t dt) {
|
||||
// TODO "step" does not work as expected
|
||||
// TODO "doStep" does not work as expected
|
||||
if (alive) {
|
||||
fade = step(fade, 0.0, 255.0, 200000, +dt);
|
||||
} else {
|
||||
|
||||
@ -69,7 +69,7 @@ public:
|
||||
return "???";
|
||||
}
|
||||
|
||||
void step(microseconds_t dt) override {
|
||||
void doStep(microseconds_t dt) override {
|
||||
runtime += dt;
|
||||
if (runtime >= 500000) {
|
||||
runtime = 0;
|
||||
|
||||
@ -1,29 +1,93 @@
|
||||
#ifndef MODE_H
|
||||
#define MODE_H
|
||||
|
||||
#define TIMER_COUNT 10
|
||||
|
||||
#include "BASICS.h"
|
||||
#include "display/Display.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class Mode {
|
||||
|
||||
private:
|
||||
|
||||
Timer *timers[TIMER_COUNT]{};
|
||||
|
||||
uint8_t timerCount = 0;
|
||||
|
||||
protected:
|
||||
|
||||
Display *display;
|
||||
|
||||
microseconds_t clock;
|
||||
|
||||
public:
|
||||
|
||||
explicit Mode(Display *display) :
|
||||
display(display) {
|
||||
// nothing
|
||||
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) {
|
||||
*timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Mode() = default;
|
||||
virtual ~Mode() {
|
||||
destroyAllTimers();
|
||||
};
|
||||
|
||||
virtual const char *getName() = 0;
|
||||
|
||||
virtual void step(microseconds_t dt) = 0;
|
||||
void step(microseconds_t dt) {
|
||||
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) {
|
||||
if (*timer != nullptr) {
|
||||
(*timer)->step(dt);
|
||||
}
|
||||
}
|
||||
doStep(dt);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void doStep(microseconds_t dt) {};
|
||||
|
||||
Timer *createTimer(microseconds_t interval, Timer::Callback callback) {
|
||||
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) {
|
||||
if (*timer == nullptr) {
|
||||
*timer = new Timer(interval, callback);
|
||||
timerCount++;
|
||||
Serial.printf("Timer created: %p (having %u now)\n", *timer, timerCount);
|
||||
return *timer;
|
||||
}
|
||||
}
|
||||
Serial.printf("ERROR: Cannot create more than %d timers!\n", TIMER_COUNT);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool destroyTimer(Timer *t) {
|
||||
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) {
|
||||
if (*timer == t) {
|
||||
_destroyTimer(timer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Serial.printf("ERROR: No such timer.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void destroyAllTimers() {
|
||||
for (Timer **timer = timers; timer < timers + TIMER_COUNT; timer++) {
|
||||
if (*timer != nullptr) {
|
||||
_destroyTimer(timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void _destroyTimer(Timer **timer) {
|
||||
timerCount--;
|
||||
free(*timer);
|
||||
Serial.printf("Timer destroyed: %p (having %u now)\n", *timer, timerCount);
|
||||
*timer = nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -7,10 +7,28 @@ class Player {
|
||||
|
||||
public:
|
||||
|
||||
int8_t position = 0;
|
||||
uint8_t position = 0;
|
||||
|
||||
uint8_t size = 2;
|
||||
|
||||
uint8_t score = 0;
|
||||
|
||||
bool moveUp = false;
|
||||
|
||||
void randomMove(uint8_t height) {
|
||||
if (moveUp) {
|
||||
position--;
|
||||
if (position <= 0 || randomBool(20)) {
|
||||
moveUp = !moveUp;
|
||||
}
|
||||
} else {
|
||||
position++;
|
||||
if (position + size >= height || randomBool(20)) {
|
||||
moveUp = !moveUp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
12
src/mode/Pong/Pong.cpp
Normal file
12
src/mode/Pong/Pong.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "Pong.h"
|
||||
|
||||
Pong *Pong::instance = nullptr;
|
||||
|
||||
void Pong::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;
|
||||
}
|
||||
@ -9,6 +9,12 @@ class Pong : public Mode {
|
||||
|
||||
private:
|
||||
|
||||
enum Status {
|
||||
SCORE, PLAY, OVER
|
||||
};
|
||||
|
||||
static Pong *instance;
|
||||
|
||||
Player player0;
|
||||
|
||||
Player player1;
|
||||
@ -17,17 +23,119 @@ private:
|
||||
|
||||
Vector velocity;
|
||||
|
||||
Status status = PLAY;
|
||||
|
||||
microseconds_t timeout = 0;
|
||||
|
||||
static void tick(Timer *timer, uint32_t totalCount, uint32_t currentCount) {
|
||||
instance->_tick(timer, totalCount, currentCount);
|
||||
}
|
||||
|
||||
void resetPlayer();
|
||||
|
||||
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)) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
static int8_t randomSignum() {
|
||||
return random(2) == 0 ? -1 : +1;
|
||||
instance = this;
|
||||
createTimer(100000, &tick);
|
||||
spawnBall(random(2) == 0 ? -1 : +1);
|
||||
resetPlayer();
|
||||
}
|
||||
|
||||
~Pong() override = default;
|
||||
@ -36,10 +144,6 @@ public:
|
||||
return "Pong";
|
||||
}
|
||||
|
||||
void step(microseconds_t dt) override {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -68,7 +68,7 @@ public:
|
||||
return "Space Invaders";
|
||||
}
|
||||
|
||||
void step(microseconds_t dt) override {
|
||||
void doStep(microseconds_t dt) override {
|
||||
stepRockets(dt);
|
||||
stepInvaders(dt);
|
||||
stepHero(dt);
|
||||
@ -80,7 +80,7 @@ public:
|
||||
Serial.println("WINNER!");
|
||||
reset();
|
||||
}
|
||||
if (swarmY + (invadersCountY - 1) * 2 >= display->height - 1) { // TODO this is only correct if there still are any invaders in the last row (otherwise we "Game Over" too early)
|
||||
if (swarmY + (invadersCountY - 1) * 2 >= display->height - 1) { // TODO this is only correct if there still are any invaders in the accu row (otherwise we "Game Over" too early)
|
||||
Serial.println("GAME OVER");
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ public:
|
||||
return "Border";
|
||||
}
|
||||
|
||||
void step(microseconds_t dt) override {
|
||||
void doStep(microseconds_t dt) override {
|
||||
for (int y = 0; y < display->height; y++) {
|
||||
for (int x = 0; x < display->width; x++) {
|
||||
if (x == 0 || x == display->width - 1 || y == 0 || y == display->height - 1) {
|
||||
|
||||
41
src/mode/Timer.h
Normal file
41
src/mode/Timer.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include "BASICS.h"
|
||||
|
||||
class Timer {
|
||||
|
||||
public:
|
||||
|
||||
typedef void (*Callback)(Timer *timer, uint32_t counter, uint32_t currentCount);
|
||||
|
||||
private:
|
||||
|
||||
Callback callback;
|
||||
|
||||
microseconds_t accu = 0;
|
||||
|
||||
uint32_t totalCount = 0;
|
||||
|
||||
public:
|
||||
|
||||
microseconds_t interval;
|
||||
|
||||
Timer(microseconds_t interval, Callback callback) :
|
||||
callback(callback),
|
||||
interval(interval) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
void step(microseconds_t dt) {
|
||||
accu += dt;
|
||||
if (accu >= interval) {
|
||||
uint32_t currentCount = accu / interval;
|
||||
accu = accu % interval;
|
||||
callback(this, totalCount++, currentCount);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user