diff --git a/src/display/Display.h b/src/display/Display.h index 26c7f45..ee223b0 100644 --- a/src/display/Display.h +++ b/src/display/Display.h @@ -107,8 +107,8 @@ public: return DISPLAY_CHAR_WIDTH; } - void set(Vector *pos, Color color) { - set((uint8_t) round(pos->x), (uint8_t) round(pos->y), color); + void set(Vector pos, Color color) { + set((uint8_t) round(pos.x), (uint8_t) round(pos.y), color); } void set(uint8_t x, uint8_t y, Color color) { diff --git a/src/display/Vector.h b/src/display/Vector.h index b61a886..3896d03 100644 --- a/src/display/Vector.h +++ b/src/display/Vector.h @@ -11,63 +11,66 @@ public: double y; + double length; + Vector() : - x(0.0), y(0.0) { + x(0.0), y(0.0), length(0.0) { // nothing } Vector(double x, double y) : - x(x), y(y) { + x(x), y(y), length(sqrt(x * x + y * y)) { // nothing } - Vector(long degrees, double length) { + static Vector polar(long degrees, double length) { double radians = (double) degrees * DEG_TO_RAD; - x = cos(radians) * length; - y = sin(radians) * length; + return { + cos(radians) * length, + sin(radians) * length, + }; } - Vector *set(Vector that) { - this->x = that.x; - this->y = that.y; - return this; + Vector plus(double _x, double _y) const { + return {x + _x, y + _y}; } - Vector *set(double _x, double _y) { - this->x = _x; - this->y = _y; - return this; + Vector plus(Vector vector) const { + return {x + vector.x, y + vector.y}; } - Vector *add(double _x, double _y) { - this->x += _x; - this->y += _y; - return this; + Vector minus(double _x, double _y) const { + return {x - _x, y - _y}; } - Vector *add(Vector that) { - this->x += that.x; - this->y += that.y; - return this; + Vector minus(Vector vector) const { + return {x - vector.x, y - vector.y}; } - 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; + Vector multiply(double i) const { + return {x * i, y * i}; + } + + Vector bounceInBox(uint8_t width, uint8_t height) const { + double x2 = this->x; + double y2 = this->y; + while (x2 < 0 || x2 >= width) { + if (x2 < 0) { + x2 = -x2; + } else if (x2 >= width) { + x2 = 2 * width - x2; } } - while (y < 0 || y >= height) { - if (y < 0) { - y = -y; - } else if (y >= height) { - y = 2 * height - y; + while (y2 < 0 || y2 >= height) { + if (y2 < 0) { + y2 = -y2; + } else if (y2 >= height) { + y2 = 2 * height - y2; } } - return this; + return {x2, y2}; } + }; #endif diff --git a/src/mode.cpp b/src/mode.cpp index 421f59a..5fb99fe 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -6,6 +6,7 @@ #include "mode/Pong/Pong.h" #include "mode/SpaceInvaders/SpaceInvaders.h" #include "mode/NewYear/NewYear.h" +#include "mode/Starfield/Starfield.h" #include "display.h" ModeId currentModeId = NONE; @@ -85,6 +86,9 @@ void loadNewMode() { case NEW_YEAR: mode = new NewYear(&display); break; + case STARFIELD: + mode = new Starfield(&display); + break; default: Serial.print("No mode loaded.\n"); display.clear(); diff --git a/src/mode/Mode.h b/src/mode/Mode.h index 315037e..349e158 100644 --- a/src/mode/Mode.h +++ b/src/mode/Mode.h @@ -19,6 +19,7 @@ enum ModeId { PONG, SPACE_INVADERS, NEW_YEAR, + STARFIELD, }; template diff --git a/src/mode/NewYear/Firework.h b/src/mode/NewYear/Firework.h index 10fd5ec..97f8ed3 100644 --- a/src/mode/NewYear/Firework.h +++ b/src/mode/NewYear/Firework.h @@ -13,7 +13,7 @@ class Firework { Display *display{}; - Color color; + Color color = MAGENTA; State state = RISE; @@ -37,7 +37,7 @@ public: } void reset() { - position.set((double) random(display->width), display->height); + position = Vector((double) random(display->width), display->height); color = randomColor(); state = INITIAL; @@ -93,38 +93,37 @@ public: } void draw() { - Vector p; switch (state) { case INITIAL: break; case RISE: - display->set(&position, YELLOW); + display->set(position, YELLOW); break; case EXPLODE: - drawParticle(p, +0.0, +1.0); - drawParticle(p, +0.7, +0.7); - drawParticle(p, +1.0, +0.0); - drawParticle(p, +0.7, -0.7); - drawParticle(p, +0.0, -1.0); - drawParticle(p, -0.7, -0.7); - drawParticle(p, -1.0, +0.0); - drawParticle(p, -0.7, +0.7); + drawParticle(+0.0, +1.0); + drawParticle(+0.7, +0.7); + drawParticle(+1.0, +0.0); + drawParticle(+0.7, -0.7); + drawParticle(+0.0, -1.0); + drawParticle(-0.7, -0.7); + drawParticle(-1.0, +0.0); + drawParticle(-0.7, +0.7); break; case SPARKLE: - if (randomBool(2)) drawParticle(p, +0.0, +1.0); - if (randomBool(2)) drawParticle(p, +0.7, +0.7); - if (randomBool(2)) drawParticle(p, +1.0, +0.0); - if (randomBool(2)) drawParticle(p, +0.7, -0.7); - if (randomBool(2)) drawParticle(p, +0.0, -1.0); - if (randomBool(2)) drawParticle(p, -0.7, -0.7); - if (randomBool(2)) drawParticle(p, -1.0, +0.0); - if (randomBool(2)) drawParticle(p, -0.7, +0.7); + if (randomBool(2)) drawParticle(+0.0, +1.0); + if (randomBool(2)) drawParticle(+0.7, +0.7); + if (randomBool(2)) drawParticle(+1.0, +0.0); + if (randomBool(2)) drawParticle(+0.7, -0.7); + if (randomBool(2)) drawParticle(+0.0, -1.0); + if (randomBool(2)) drawParticle(-0.7, -0.7); + if (randomBool(2)) drawParticle(-1.0, +0.0); + if (randomBool(2)) drawParticle(-0.7, +0.7); break; } } - void drawParticle(Vector &p, double x, double y) { - display->set(p.set(position)->add(x * explosion, y * explosion), color); + void drawParticle(double x, double y) { + display->set(position.plus(x * explosion, y * explosion), color); } bool isAlive() { diff --git a/src/mode/Pong/Pong.h b/src/mode/Pong/Pong.h index f770e29..21e8708 100644 --- a/src/mode/Pong/Pong.h +++ b/src/mode/Pong/Pong.h @@ -43,7 +43,7 @@ private: } break; case PLAY: - position.add(velocity); + position = position.plus(velocity); player0.randomMove(display->height); player1.randomMove(display->height); paddleBounce(); @@ -63,7 +63,7 @@ private: } void topBottomBounce() { - position.bounceInBox(display->width, display->height); + position = position.bounceInBox(display->width, display->height); } void checkScoring() { @@ -132,7 +132,7 @@ public: explicit Pong(Display *display) : Mode(display), position(display->width / 2.0, display->height / 2.0), - velocity(random(360), exp10(1)) { + velocity(Vector::polar(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); diff --git a/src/mode/Starfield/Starfield.h b/src/mode/Starfield/Starfield.h new file mode 100644 index 0000000..da409bc --- /dev/null +++ b/src/mode/Starfield/Starfield.h @@ -0,0 +1,46 @@ +#ifndef MEDIATABLE_STARFIELD_H +#define MEDIATABLE_STARFIELD_H + +#include "mode/Mode.h" + +#define STAR_COUNT 20 + +class Starfield : public Mode { + +private: + + Vector center; + + Vector stars[STAR_COUNT]; + +public: + + explicit Starfield(Display *display) : + Mode(display), + center(display->width / 2.0, display->height / 2.0) { + for (auto &star: stars) { + star.x = random(display->width); + star.y = random(display->height); + } + } + + const char *getName() override { + return "Starfield"; + } + + void doStep(microseconds_t dt) override { + display->clear(); + for (auto &star: stars) { + const Vector velocity = star.minus(center).multiply((double) dt / 200000.0); + star = star.plus(velocity); + if (star.x < 0 || star.x >= display->width || star.y < 0 || star.y >= display->height) { + star = center.plus(Vector::polar(random(360), 1)); + } + uint8_t brightness = (uint8_t) round(255.0 * star.minus(center).length / (display->width / 2.0)); + display->set(star, gray(brightness)); + } + } + +}; + +#endif diff --git a/src/server.cpp b/src/server.cpp index 0efe556..d95ca3f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -59,6 +59,7 @@ void web_index() { server.sendContent(R"(PONG
)"); server.sendContent(R"(SPACE_INVADERS
)"); server.sendContent(R"(NEW_YEAR
)"); + server.sendContent(R"(STARFIELD
)"); server.sendContent(R"(Helligkeit: + / -
)"); server.sendContent(R"(Geschwindigkeit: + / -
)");