149 lines
3.6 KiB
C++
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
|