RGBMatrixDisplay/src/mode/NewYear/Firework.h
2021-12-31 15:29:38 +01:00

137 lines
3.1 KiB
C++

#ifndef NEW_YEAR_FIREWORK_H
#define NEW_YEAR_FIREWORK_H
#include "BASICS.h"
#include "display/Vector.h"
#include "display/Display.h"
class Firework {
enum State {
INITIAL, RISE, EXPLODE, SPARKLE
};
Display *display{};
uint32_t color{};
State state = RISE;
Vector position;
double destinationHeight = 0;
double explosionRadius = 0;
double sparkleMax = 0;
double explosion{};
double sparkle{};
public:
void init(Display *_display) {
this->display = _display;
reset();
}
void reset() {
position.set((double) random(display->width), display->height);
color = random(16777216);
state = INITIAL;
destinationHeight = display->height / 2.0 + (double) random(5) - 2;
explosionRadius = (double) random(3) + 1;
sparkleMax = 100;
explosion = 0.0;
sparkle = 0.0;
}
void launch() {
if (state != INITIAL) {
Serial.println("ERROR: Cannot start Firework. Already started.");
return;
}
state = RISE;
}
void step(microseconds_t dt) {
switch (state) {
case INITIAL:
break;
case RISE:
if (position.y <= destinationHeight) {
state = EXPLODE;
}
break;
case EXPLODE:
if (explosion >= explosionRadius) {
state = SPARKLE;
}
break;
case SPARKLE:
if (sparkle >= sparkleMax) {
reset();
}
break;
}
switch (state) {
case INITIAL:
break;
case RISE:
position.y = doStep(position.y, 0.0, display->height, 1000, -dt);
break;
case EXPLODE:
explosion = doStep(explosion, 0.0, explosionRadius, 500, +dt);
break;
case SPARKLE:
sparkle = doStep(sparkle, 0.0, sparkleMax, 1000, +dt);
break;
}
}
void draw() {
Vector p;
switch (state) {
case INITIAL:
break;
case RISE:
display->set(&position, COLOR_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);
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);
break;
}
}
void drawParticle(Vector &p, double x, double y) {
display->set(p.set(position)->add(x * explosion, y * explosion), color);
}
bool isAlive() {
return state != INITIAL;
}
};
#endif