Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@jpro56
Created May 25, 2015 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpro56/a98279acc78ec7bd2af5 to your computer and use it in GitHub Desktop.
Save jpro56/a98279acc78ec7bd2af5 to your computer and use it in GitHub Desktop.
My fireworks on a 16x25 Ws2812b array using Arduino MEGA 2560
#include "FastLED.h"
// Originaly designed for a 16x16 matrix by Mark Kriegsman, July 2013
// Updated for a 16 strip X 25 WS2812b LED array with each strip driven by a separate pin
// Modified to have multiple shell launch and did some code clean-up wehe possible.
#define PIXEL_WIDTH 16
#define PIXEL_HEIGHT 25
CRGB leds[PIXEL_WIDTH][PIXEL_HEIGHT];
CRGB overrun;
CRGB& XY( uint8_t x, uint8_t y)
{
if( x < PIXEL_WIDTH && y < PIXEL_HEIGHT && x >= 0 && y >= 0) return leds[x][y];
else return overrun; // In case pixel is outside the LED array, return the address of a dummy CRGB value
}
void screenscale( accum88 hor, accum88 ver, fract8& pixel, fract8& up, fract8& right, fract8& diag) // 3 Pointers to resulting fract8 variables
{
fract8 x_fract = (hor >> 7) & 15; // Extracts only the fractional part (in 1/16th) of the pixel position
fract8 y_fract = (ver >> 7) & 15;
diag = x_fract * y_fract; // Returns a number representing the proportion (in 1/256th) for each of the 4 pixels
up = (16 - x_fract) * y_fract;
right = (16 - y_fract) * x_fract;
pixel = 256 - (16 * x_fract) - (16 * y_fract) + diag;
/*
Serial.print("Hor = ");
Serial.print(hor);
Serial.print(" , Ver = ");
Serial.print(ver);
Serial.print(" , x_fract = ");
Serial.print(x_fract);
Serial.print(" , y_fract = ");
Serial.print(y_fract);
Serial.print(" , diag = ");
Serial.print(diag);
Serial.print(" , up = ");
Serial.print(up);
Serial.print(" , right = ");
Serial.print(right);
Serial.print(" , pixel = ");
Serial.println(pixel);
*/
}
uint8_t gGravity = 2; //11
uint8_t gDrag = 1;
accum88 gBurstx;
accum88 gBursty;
saccum78 gBurstxv;
saccum78 gBurstyv;
CRGB gBurstcolor;
#define NONE 0
#define SHELL 1
#define SPARK 2
#define EXPLODING 3
#define BURSTING 4
class Dot {
public:
int8_t show;
int8_t theType;
accum88 x;
accum88 y;
saccum78 xv;
saccum78 yv;
CRGB color;
Dot() // Constructor for the Dot class
{
show = 0;
theType = 0;
x = 0;
y = 0;
xv = 0;
yv = 0;
color.setRGB( 0, 0, 0);
}
void Draw()
{
fract8 p00, p01, p10, p11; // percentage of pixel spread to adjacent pixels
screenscale( x, y, p00, p01, p10, p11);
uint8_t x_pos = x >> 11; // Scaling to get x and y pixel positions
uint8_t y_pos = y >> 11;
if (yv > 0){ // In case of equal values, just adding 1 or 2 to any pixel's percentage
if (p00 == p01) p01++; // will ensure than only one pixel will have a higher percentage than
if (p10 == p11) p11++; // any of the other 3
}
if (yv <0){
if (p00 == p01) p00++;
if (p10 == p11) p10++;
}
if (xv > 0){
if (p00 == p10) p10++;
if (p01 == p11) p11++;
}
if (xv <0){
if (p00 == p10) p00++;
if (p01 == p11) p01++;
}
if( !show) return;
if ((p00 > p01) && (p00 > p10) && (p00 > p11)) XY(x_pos, y_pos) += color;
if ((p01 > p00) && (p01 > p10) && (p01 > p11)) XY(x_pos, y_pos + 1) += color;
if ((p10 > p00) && (p10 > p01) && (p10 > p11)) XY(x_pos + 1, y_pos) += color;
if ((p11 > p00) && (p11 > p01) && (p11 > p10)) XY(x_pos + 1, y_pos + 1) += color;
/*
XY(x_pos, y_pos) = CRGB(p00, p00, p00); // Modifies the color content of the base pixel
XY(x_pos, y_pos + 1) = CRGB(p01, p01, p01); // and the 3 immediate pixels on top, to the right and diagonal
XY(x_pos + 1, y_pos) = CRGB(p10, p10, p10);
XY(x_pos + 1, y_pos + 1) = CRGB(p11, p11, p11);
*/
} // End of draw function
void Move()
{
// if( !show) return;
if(((xv > 0) && (x+xv < xv)) || ((xv < 0) && (x+xv > xv))) show = 0; // Prevents pixels wraparounds from side to side
if(((yv > 0) && (y+yv < yv))) show = 0; // Prevents pixels wraparounds from top to bottom
if( yv < 0 && (y < (-yv)) ) show = 0; // If velocity is negative AND we are about to hit the ground
if (theType == EXPLODING) { // If the Shell has exploded...
show = 0;
theType = BURSTING; // prepare for a burst on next frame
// gBurstx = x;
// gBursty = y;
// gBurstxv = xv;
// gBurstyv = yv;
// hsv2rgb_rainbow( CHSV( random8(), 240, 200), gBurstcolor);
}
if ((yv < 0) && (theType == SHELL)) { // If velocity is negative AND it is a shell...
xv=0; // Stop further movements
yv=0;
color = CRGB(255, 255, 255); // Set full brightness white color
theType = EXPLODING; // explode the shell !!
}
x += xv;
y += yv;
yv -= gGravity;
if (xv>0) xv -= gDrag;
if (xv<0) xv += gDrag;
if (yv>0) yv -= gDrag;
if (yv<0) yv += gDrag;
} //End of the move function
void GroundLaunch()
{
yv = 450 + random16(100); // Generates an unsigned int value between 450 and 550 (Nice height but always inside of frame)
xv = (int16_t)random16(350) - (int16_t) 175; // Generates a signed int value between +/- 175 (Nice width but always inside of frame)
y = 0; // Ground launch
x = 0x4000; // Horizontal middle of screen
color.setRGB(16,16,16); // Shells are white color' as a CRGB
theType = SHELL;
show = 1;
} //End of Groundlaunch function
void Skyburst( accum88 basex, accum88 basey, CRGB& basecolor)
{
yv = random16(400) - 200; // Random number (Y-velocity) between -600 and +600
xv = random16(400) - 200; // Random number (X-velocity) between -600 and +600
y = basey;
x = basex;
color = basecolor;
color *= 8;
theType = SPARK;
show = 1;
} //End of Skyburst function
}; // End of Dot class definition
#define MAX_SHELLS 6
#define MIN_SHELLS 2
#define MAX_SPARKS 40
#define MIN_SPARKS 30
Dot gDot[MAX_SHELLS]; //Creates an object named gDot of type Dot class
Dot gSparks[MAX_SHELLS][MAX_SPARKS]; //Creates an array object named gSparks of type Dot class
void setup()
{
Serial.begin(38400);
FastLED.setBrightness(128);
FastLED.addLeds<NEOPIXEL, 25>(leds[0], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 24>(leds[1], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 23>(leds[2], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 22>(leds[3], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 11>(leds[4], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 10>(leds[5], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 34>(leds[6], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 35>(leds[7], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 33>(leds[8], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 31>(leds[9], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 29>(leds[10], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 27>(leds[11], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 4>(leds[12], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 41>(leds[13], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 39>(leds[14], PIXEL_HEIGHT);
FastLED.addLeds<NEOPIXEL, 37>(leds[15], PIXEL_HEIGHT);
}
void loop()
{
random16_add_entropy(analogRead(3)); // Somehow this mixes the random numbers even more !?
CRGB sky1(0,0,2); // Background sky color (will only work if brightness is set high 128 or up !!)
CRGB sky2(2,2,2); // Alternate sky color to create a star twinkle effect
for( int h = 0; h < PIXEL_WIDTH; h++) { // All leds will be set to 'sky1' (very dark blue)
for( int v = 0; v < PIXEL_HEIGHT; v++) {
leds[h][v] = sky1;
}
}
if( random8() < 32 ) leds[random16(PIXEL_WIDTH)][random16(PIXEL_HEIGHT)] = sky2; // Around once each 8 frames, a random pixel is set to 'sky2'
static uint8_t launchcountdown = 0;
static uint16_t re_launchcountdown = 0;
if(gDot[MAX_SHELLS-1].show == 0) { // If the last shell has exploded
re_launchcountdown --; // Count down for next re_launch
if (re_launchcountdown > 30000) re_launchcountdown = 0;
}
for( int a = 0; a < MAX_SHELLS; a++) // Always moves and draws the MAX number of sparks not the actual number of sparks (Wasteful!?)
{
if(re_launchcountdown == 0){
if(gDot[a].show == 0) {
if(launchcountdown == 0) {
gDot[a].GroundLaunch();
launchcountdown = random16(50) + 10;
}
else {
launchcountdown --;
if (launchcountdown > 254) launchcountdown = 0;
}
}
}
if(gDot[MAX_SHELLS-1].show == 1) re_launchcountdown = random16(400) + 100; // Last SHELL has launched, restart the relaunch timer
// if( gDot[a].theType == EXPLODING) {
// gDot[a].color.setRGB(255,255,255);
// }
if( gDot[a].theType == BURSTING) {
hsv2rgb_rainbow( CHSV( random8(), 255, random8(64,254)), gBurstcolor);
gBurstx = gDot[a].x;
gBursty = gDot[a].y;
int nsparks = random8(MIN_SPARKS, MAX_SPARKS+1);
for( int b = 0; b < nsparks; b++) {
gSparks[a][b].Skyburst( gBurstx, gBursty, gBurstcolor);
}
gDot[a].theType = SPARK;
}
gDot[a].Move(); // Calculate the next position of the dots
gDot[a].Draw(); // Scale the position of the shell on the LED matrix
for( int b = 0; b < MAX_SPARKS; b++) { // Always moves and draws the MAX number of sparks not the actual number of sparks (Wasteful!?)
gSparks[a][b].Move();
/* Serial.print("Before scaling: gSparks[");
Serial.print(a);
Serial.print("][");
Serial.print(b);
Serial.print("].color.r = ");
Serial.print(gSparks[a][b].color.r);
Serial.print(" g = ");
Serial.print(gSparks[a][b].color.g);
Serial.print(" b = ");
Serial.println(gSparks[a][b].color.b);
*/
gSparks[a][b].color.r = gSparks[a][b].color.r * 255 /256;
gSparks[a][b].color.g = gSparks[a][b].color.g * 255 /256;
gSparks[a][b].color.b = gSparks[a][b].color.b * 255 /256;
/*
Serial.print("After scaling: gSparks[");
Serial.print(a);
Serial.print("][");
Serial.print(b);
Serial.print("].color.r = ");
Serial.print(gSparks[a][b].color.r);
Serial.print(" g = ");
Serial.print(gSparks[a][b].color.g);
Serial.print(" b = ");
Serial.println(gSparks[a][b].color.b);
*/
gSparks[a][b].Draw();
}
}
FastLED.show();
//FastLED.delay(100);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment