RGBMatrixDisplay/src/mode/CountDown/CountDownFirework.h

149 lines
3.6 KiB
C++

#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