#ifndef COUNT_DOWN_FIREWORK_H #define COUNT_DOWN_FIREWORK_H #include "BASICS.h" #include "display/Vector.h" #include "display/Display.h" #define DARKER_FACTOR 0.75 #define SLOWER_DIVISOR 1 class Firework { enum State { INITIAL, RISE, EXPLODE, SPARKLE }; uint8_t width = 0; uint8_t height = 0; Color color = MAGENTA; State state = RISE; Vector position; double destinationHeight = 0; double explosionRadius = 0; double sparkleMax = 0; double explosion{}; double sparkle{}; public: void init(Display &display) { width = display.width; height = display.height; reset(); } void reset() { position = Vector((double) random(width), height); color = randomColor(); state = INITIAL; destinationHeight = height / 2.0 + (double) random(5) - 2; explosionRadius = (double) random(3) + 1; sparkleMax = 100; explosion = 0.0; sparkle = 0.0; } void step(microseconds_t microseconds) { microseconds = microseconds / SLOWER_DIVISOR; switch (state) { case INITIAL: state = RISE; break; case RISE: if (position.y > destinationHeight) { position.y = doStep(position.y, 0.0, height, 1000, -microseconds); } else { state = EXPLODE; } break; case EXPLODE: if (explosion < explosionRadius) { explosion = doStep(explosion, 0.0, explosionRadius, 500, +microseconds); } else { state = SPARKLE; } break; case SPARKLE: if (sparkle < sparkleMax) { sparkle = doStep(sparkle, 0.0, sparkleMax, 1000, +microseconds); } else { reset(); } break; } } void draw(Display &display) { switch (state) { case INITIAL: break; case RISE: display.set(position, factor(YELLOW, DARKER_FACTOR)); break; case EXPLODE: drawParticle(display, +0.0, +1.0); drawParticle(display, +0.7, +0.7); drawParticle(display, +1.0, +0.0); drawParticle(display, +0.7, -0.7); drawParticle(display, +0.0, -1.0); drawParticle(display, -0.7, -0.7); drawParticle(display, -1.0, +0.0); drawParticle(display, -0.7, +0.7); break; case SPARKLE: if (randomBool(2)) drawParticle(display, +0.0, +1.0); if (randomBool(2)) drawParticle(display, +0.7, +0.7); if (randomBool(2)) drawParticle(display, +1.0, +0.0); if (randomBool(2)) drawParticle(display, +0.7, -0.7); if (randomBool(2)) drawParticle(display, +0.0, -1.0); if (randomBool(2)) drawParticle(display, -0.7, -0.7); if (randomBool(2)) drawParticle(display, -1.0, +0.0); if (randomBool(2)) drawParticle(display, -0.7, +0.7); break; } } const char *getStateName() const { switch (state) { case INITIAL: return "INITIAL"; case RISE: return "RISE"; case EXPLODE: return "EXPLODE"; case SPARKLE: return "SPARKLE"; } return "[???]"; } private: static Color factor(Color color, double factor) { return { (uint8_t) round(color.r * factor), (uint8_t) round(color.g * factor), (uint8_t) round(color.b * factor), }; } void drawParticle(Display &display, double x, double y) { display.set(position.plus(x * explosion, y * explosion), factor(color, DARKER_FACTOR)); } }; #endif