initial commit
This commit is contained in:
+878
@@ -0,0 +1,878 @@
|
||||
#include "animation.h"
|
||||
#include <math.h>
|
||||
#include <pgmspace.h>
|
||||
|
||||
#define WIDTH 20
|
||||
#define HEIGHT 20
|
||||
|
||||
#define SIN_TABLE_SIZE 256
|
||||
#define TWO_PI 6.28318530717958647692f
|
||||
#define INV_TWO_PI (1.0f / TWO_PI)
|
||||
|
||||
const float sinTable[SIN_TABLE_SIZE] PROGMEM = {
|
||||
#include "sin_table_256.inc"
|
||||
};
|
||||
|
||||
// Pumpkin pixel art 8x8 (simplified)
|
||||
// 0 = empty, 1 = pumpkin body, 2 = eye
|
||||
const uint8_t pumpkinSprite[8][8] = {
|
||||
{0,1,1,1,1,1,1,0},
|
||||
{1,1,1,1,1,1,1,1},
|
||||
{1,2,0,1,1,0,2,1},
|
||||
{1,1,1,1,1,1,1,1},
|
||||
{1,1,1,0,0,1,1,1},
|
||||
{1,1,0,1,1,0,1,1},
|
||||
{0,1,1,1,1,1,1,0},
|
||||
{0,0,1,1,1,1,0,0}
|
||||
};
|
||||
|
||||
const uint8_t imageManuBude[20][20] = {
|
||||
{0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1},
|
||||
{0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
};
|
||||
|
||||
// Colors
|
||||
uint32_t pumpkinColor = Adafruit_NeoPixel::Color(255,140,0); // orange
|
||||
uint32_t eyeBaseColor = Adafruit_NeoPixel::Color(255,60,0); // fiery red-orange
|
||||
|
||||
static inline float sinPreCalc(float value)
|
||||
{
|
||||
// Scale factor (precompute once as constant)
|
||||
const float scale = SIN_TABLE_SIZE / TWO_PI;
|
||||
|
||||
// Convert radians → table index (float)
|
||||
float index = value * scale;
|
||||
|
||||
// Convert to integer index
|
||||
int i0 = (int)index;
|
||||
|
||||
// Fractional part for interpolation
|
||||
float frac = index - i0;
|
||||
|
||||
// Wrap index using power-of-two mask (256 -> 0xFF)
|
||||
i0 &= (SIN_TABLE_SIZE - 1);
|
||||
int i1 = (i0 + 1) & (SIN_TABLE_SIZE - 1);
|
||||
|
||||
// Read from flash
|
||||
float s0 = pgm_read_float(&sinTable[i0]);
|
||||
float s1 = pgm_read_float(&sinTable[i1]);
|
||||
|
||||
// Linear interpolation
|
||||
return s0 + frac * (s1 - s0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Bubble animation function
|
||||
uint32_t bubbles(uint8_t x, uint8_t y, float timeMs) {
|
||||
float colorR = 0, colorG = 0, colorB = 0;
|
||||
|
||||
// Generate several bubbles per column
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
// Each bubble has its own horizontal position and speed
|
||||
float speed = 0.02f + 0.01f * (hash8(i*3, x)/255.0f); // pixels/ms
|
||||
float phase = hash8(i*7, x)/255.0f * HEIGHT; // starting row
|
||||
float bubbleY = fmod((timeMs*speed + phase), HEIGHT);
|
||||
|
||||
// Distance from this bubble to pixel
|
||||
float dist = fabs(bubbleY - y);
|
||||
if (dist < 1.5) { // bubble radius
|
||||
// Brightness fades at edges
|
||||
float brightness = 1.0f - (dist/1.5f);
|
||||
colorR += 100 * brightness;
|
||||
colorG += 180 * brightness;
|
||||
colorB += 255 * brightness;
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp colors
|
||||
if (colorR > 255) colorR = 255;
|
||||
if (colorG > 255) colorG = 255;
|
||||
if (colorB > 255) colorB = 255;
|
||||
|
||||
return Adafruit_NeoPixel::Color((uint8_t)colorR, (uint8_t)colorG, (uint8_t)colorB);
|
||||
}
|
||||
|
||||
// Pseudo-random flicker
|
||||
float flicker(float timeMs, uint8_t seed) {
|
||||
return 0.6f + 0.4f * sinPreCalc(timeMs*0.01f + seed*3.14f); // 0.6..1.0
|
||||
}
|
||||
|
||||
// Pumpkin pixel function
|
||||
uint32_t minecraftPumpkin(uint8_t x, uint8_t y, float timeMs) {
|
||||
int spriteWidth = 8;
|
||||
int spriteHeight = 8;
|
||||
int offsetX = WIDTH/2 - spriteWidth/2;
|
||||
int offsetY = HEIGHT/2 - spriteHeight/2;
|
||||
|
||||
int localX = x - offsetX;
|
||||
int localY = y - offsetY;
|
||||
|
||||
if (localX >= 0 && localX < spriteWidth && localY >= 0 && localY < spriteHeight) {
|
||||
uint8_t val = pumpkinSprite[localY][localX];
|
||||
if (val == 1) return pumpkinColor;
|
||||
if (val == 2) {
|
||||
// Flickering fire eyes
|
||||
float f = flicker(timeMs, localX*10 + localY);
|
||||
uint8_t r = (uint8_t)(255 * f);
|
||||
uint8_t g = (uint8_t)(60 * f);
|
||||
uint8_t b = 0;
|
||||
return Adafruit_NeoPixel::Color(r,g,b);
|
||||
}
|
||||
}
|
||||
return Adafruit_NeoPixel::Color(0,0,0); // background black
|
||||
}
|
||||
|
||||
|
||||
// Among Us pixel art 7x7 (simplified)
|
||||
// 0 = empty, 1 = body, 2 = visor
|
||||
const uint8_t amongUsSprite[8][8] = {
|
||||
{0,0,1,1,1,1,0,0},
|
||||
{0,1,1,3,3,3,3,0},
|
||||
{1,1,3,2,2,2,2,3},
|
||||
{1,1,3,2,2,2,2,3},
|
||||
{1,1,1,3,3,3,3,0},
|
||||
{1,1,1,1,1,1,1,0},
|
||||
{0,1,1,1,1,1,1,0},
|
||||
{0,1,1,0,0,1,1,0}
|
||||
};
|
||||
|
||||
// Colors
|
||||
uint32_t bodyColor = Adafruit_NeoPixel::Color(255,0,0); // red crewmate
|
||||
uint32_t visorColor = Adafruit_NeoPixel::Color(150,200,255); // visor
|
||||
uint32_t visorColorInner = Adafruit_NeoPixel::Color(0,0,255); // visor
|
||||
|
||||
// Function to get pixel color of Among Us crewmate
|
||||
uint32_t amongUsPixel(uint8_t x, uint8_t y, float timeMs) {
|
||||
// Move crewmate horizontally across screen
|
||||
int spriteWidth = 8;
|
||||
int spriteHeight = 8;
|
||||
|
||||
int posX = (int)(fmod(timeMs * 0.01f, WIDTH + spriteWidth)) - spriteWidth;
|
||||
int posY = HEIGHT / 2 - spriteHeight / 2;
|
||||
|
||||
int localX = x - posX;
|
||||
int localY = y - posY;
|
||||
|
||||
if (localX >= 0 && localX < spriteWidth && localY >= 0 && localY < spriteHeight) {
|
||||
uint8_t val = amongUsSprite[localY][localX];
|
||||
if (val == 1) return bodyColor;
|
||||
if (val == 2) return visorColorInner;
|
||||
if (val == 3) return visorColor;
|
||||
}
|
||||
|
||||
return Adafruit_NeoPixel::Color(0,0,0); // background black
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Fast pseudo-random hash function (per pixel)
|
||||
uint8_t hash8(uint16_t x, uint16_t y) {
|
||||
uint32_t h = x * 374761393 + y * 668265263; // large primes
|
||||
h = (h ^ (h >> 13)) * 1274126177;
|
||||
return (h >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
// Purple rain waterfall color function
|
||||
uint32_t purpleRain(uint8_t x, uint8_t y, float timeMs) {
|
||||
// Each column has its own speed
|
||||
float speed = 0.03f + 0.01f * (hash8(x, 0) / 255.0f); // pixels/ms
|
||||
float t = timeMs * speed;
|
||||
|
||||
// Determine the head of the falling stream
|
||||
int headRow = (int)t % HEIGHT;
|
||||
|
||||
// Distance from head
|
||||
int dist = (y + HEIGHT - headRow) % HEIGHT;
|
||||
|
||||
// Brightness fades with distance
|
||||
uint8_t brightness = 0;
|
||||
if (dist == 0) brightness = 255; // brightest head
|
||||
else if (dist < 6) brightness = 255 - dist * 60; // fading tail
|
||||
else brightness = 0;
|
||||
|
||||
// Purple color: R and B nonzero, G low
|
||||
uint8_t r = brightness;
|
||||
uint8_t g = brightness / 2; // small green tint
|
||||
uint8_t b = brightness;
|
||||
|
||||
return Adafruit_NeoPixel::Color(r, g, b);
|
||||
}
|
||||
// Starry sky function
|
||||
uint32_t starrySky(uint8_t x, uint8_t y, float timeMs) {
|
||||
uint8_t seed = hash8(x, y);
|
||||
|
||||
// Only ~5% of pixels have stars
|
||||
if (seed < 20) { // 0..12
|
||||
// Twinkle: small brightness variation
|
||||
float phase = (timeMs * 0.002f + seed) * 0.1f;
|
||||
float blink = 0.7f + 0.8f * sinPreCalc(phase * 6.2831f); // 0.4..1.0
|
||||
uint8_t brightness = (uint8_t)(150 * blink + 50); // 50..200
|
||||
return Adafruit_NeoPixel::Color(brightness, brightness, brightness);
|
||||
}
|
||||
|
||||
// Shooting star: rare (~0.5%) moving diagonally
|
||||
float t = fmod(timeMs * 0.01f, WIDTH + HEIGHT);
|
||||
if (seed > 250 && fabs(x - t) < 1 && fabs(y - t) < 1) {
|
||||
return Adafruit_NeoPixel::Color(255, 200, 150);
|
||||
}
|
||||
|
||||
// Otherwise empty sky
|
||||
return Adafruit_NeoPixel::Color(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
uint32_t spinningDavidStarPixel(uint8_t x, uint8_t y, float timeMs) {
|
||||
float t = timeMs * 0.001f; // seconds
|
||||
|
||||
// Center of the matrix
|
||||
float cx = 10.0f;
|
||||
float cy = 10.0f;
|
||||
|
||||
// Translate to center
|
||||
float dx = x - cx;
|
||||
float dy = y - cy;
|
||||
|
||||
// Rotation angle
|
||||
float angle = t * 2.0f; // radians, spins over time
|
||||
float cosA = sinPreCalc(TWO_PI/4 - angle);
|
||||
float sinA = sinPreCalc(angle);
|
||||
|
||||
float rx = dx * cosA - dy * sinA;
|
||||
float ry = dx * sinA + dy * cosA;
|
||||
|
||||
// Star of David = two overlapping equilateral triangles
|
||||
// Approximate with slopes: y = ±sqrt(3)*x for the triangles
|
||||
|
||||
bool inStar = false;
|
||||
|
||||
// Upper triangle
|
||||
if (ry >= -rx * 1.7f && ry >= rx * 1.7f && ry <= 0) inStar = true;
|
||||
// Lower triangle
|
||||
if (ry <= -rx * 1.7f && ry <= rx * 1.7f && ry >= 0) inStar = true;
|
||||
|
||||
// Draw the star
|
||||
if (inStar) {
|
||||
// Optional: pulsating color
|
||||
uint8_t pulse = 150 + 105 * sinPreCalc(t * 3.0f);
|
||||
return NeoPixel.Color(pulse, pulse, 255);
|
||||
}
|
||||
|
||||
// Background
|
||||
return NeoPixel.Color(0, 0, 20);
|
||||
}
|
||||
|
||||
|
||||
uint32_t jumpingJackPixel(uint8_t x, uint8_t y, float timeMs) {
|
||||
float t = timeMs * 0.001f; // seconds
|
||||
|
||||
// Center of the stick figure
|
||||
int cx = 10;
|
||||
int cy = 12;
|
||||
|
||||
// Oscillation amplitudes
|
||||
float armSpread = 4.0f * sinPreCalc(t * 2.0f); // arms
|
||||
float legSpread = 4.0f * sinPreCalc(t * 2.0f); // legs
|
||||
float jump = sinPreCalc(t * 2.0f) * -3.0f; // up/down jump
|
||||
|
||||
// Background
|
||||
uint32_t bg = NeoPixel.Color(0, 0, 0);
|
||||
|
||||
// -----------------
|
||||
// Head (3x3)
|
||||
// -----------------
|
||||
int headY = cy - 5 + (int)jump;
|
||||
if ((x >= cx - 1 && x <= cx + 1) && (y >= headY && y <= headY + 2)) {
|
||||
return NeoPixel.Color(255, 255, 255);
|
||||
}
|
||||
|
||||
// -----------------
|
||||
// Body (vertical)
|
||||
// -----------------
|
||||
int bodyTop = cy - 2 + (int)jump;
|
||||
int bodyBottom = cy + 2 + (int)jump;
|
||||
if (x == cx && y >= bodyTop && y <= bodyBottom) {
|
||||
return NeoPixel.Color(255, 255, 255);
|
||||
}
|
||||
|
||||
// -----------------
|
||||
// Arms (diagonal)
|
||||
// -----------------
|
||||
int leftArmX = cx - 1 - (int)armSpread;
|
||||
int rightArmX = cx + 1 + (int)armSpread;
|
||||
int armY = cy - 1 + (int)jump;
|
||||
|
||||
if ((x == leftArmX && y == armY - 1) || (x == leftArmX + 1 && y == armY) ||
|
||||
(x == rightArmX && y == armY - 1) || (x == rightArmX - 1 && y == armY)) {
|
||||
return NeoPixel.Color(255, 255, 255);
|
||||
}
|
||||
|
||||
// -----------------
|
||||
// Legs (diagonal)
|
||||
// -----------------
|
||||
int leftLegX = cx - 1 - (int)legSpread;
|
||||
int rightLegX = cx + 1 + (int)legSpread;
|
||||
int legY = cy + 3 + (int)jump;
|
||||
|
||||
if ((x == leftLegX && y == legY) || (x == leftLegX + 1 && y == legY + 1) ||
|
||||
(x == rightLegX && y == legY) || (x == rightLegX - 1 && y == legY + 1)) {
|
||||
return NeoPixel.Color(255, 255, 255);
|
||||
}
|
||||
|
||||
return bg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t bonfireMoonPixel(uint8_t x, uint8_t y, float timeMs) {
|
||||
float t = timeMs * 0.001f; // seconds
|
||||
|
||||
// ------------------------
|
||||
// Quarter moon (crescent)
|
||||
// ------------------------
|
||||
int moonX = 15;
|
||||
int moonY = 4;
|
||||
int moonR = 3;
|
||||
|
||||
float mdx = x - moonX;
|
||||
float mdy = y - moonY;
|
||||
float mdist = sqrt(mdx * mdx + mdy * mdy);
|
||||
|
||||
bool inMoon = (mdist <= moonR);
|
||||
|
||||
// Cut-out circle to form crescent
|
||||
float cutX = moonX + 2; // shift right to carve shadow
|
||||
float cdx = x - cutX;
|
||||
float cdist = sqrt(cdx * cdx + mdy * mdy);
|
||||
|
||||
bool inShadow = (cdist <= moonR);
|
||||
|
||||
if (inMoon && !inShadow) {
|
||||
uint8_t glow = 140 + 40 * sinPreCalc(t * 0.5f);
|
||||
return NeoPixel.Color(glow, glow, glow + 20);
|
||||
}
|
||||
|
||||
// ------------
|
||||
// Big bonfire
|
||||
// ------------
|
||||
int baseX = 10;
|
||||
int baseY = 16;
|
||||
|
||||
bool log1 = (y == baseY && x >= 4 && x <= 15);
|
||||
bool log2 = (y == baseY - 1 && x >= 5 && x <= 14);
|
||||
bool log3 = (y == baseY - 2 && x >= 7 && x <= 12);
|
||||
|
||||
if (log1 || log2 || log3) {
|
||||
return NeoPixel.Color(100, 50, 15);
|
||||
}
|
||||
|
||||
int dx = x - baseX;
|
||||
int dy = baseY - y;
|
||||
|
||||
if (dy >= 0 && dy <= 10 && abs(dx) <= (5 - dy / 2)) {
|
||||
float flicker = sinPreCalc(t * 9.0f + x * 2.1f + y * 1.4f) * 0.5f + 0.5f;
|
||||
|
||||
uint8_t r = 170 + 85 * flicker;
|
||||
uint8_t g = 70 + 160 * flicker - dy * 8;
|
||||
uint8_t b = 0;
|
||||
|
||||
return NeoPixel.Color(constrain(r, 150, 255),
|
||||
constrain(g, 40, 220),
|
||||
b);
|
||||
}
|
||||
|
||||
if (dy == 0 && abs(dx) <= 6) {
|
||||
uint8_t glow = 90 + 50 * sinPreCalc(t * 7.0f + x * 0.8f);
|
||||
return NeoPixel.Color(glow, glow / 2, 0);
|
||||
}
|
||||
|
||||
// ----------------
|
||||
// Night sky bg
|
||||
// ----------------
|
||||
uint8_t stars = 4 + 6 * sinPreCalc(t * 0.3f + x * 0.6f + y * 0.4f);
|
||||
return NeoPixel.Color(0, 0, stars);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t nyanCatPixel(uint8_t x, uint8_t y, float timeMs) {
|
||||
float t = timeMs * 0.0015f; // seconds
|
||||
|
||||
// Cat position (flies left -> right, loops)
|
||||
float catXf = fmod(t * 6.0f, 30.0f) - 6.0f; // offscreen -> onscreen
|
||||
int catX = (int)catXf;
|
||||
int catY = 10 + (int)(sinPreCalc(t * 2.0f) * 2.0f);
|
||||
|
||||
// Background space
|
||||
uint8_t stars = 5 + 10 * sinPreCalc(t * 0.7f + x * 0.9f + y * 0.4f);
|
||||
uint32_t bg = NeoPixel.Color(0, 0, stars);
|
||||
|
||||
// Rainbow trail (behind cat)
|
||||
if (x < catX && x > catX - 8 && abs(y - catY) <= 1) {
|
||||
float phase = t * 6.0f + x * 0.5f;
|
||||
uint8_t r = 127 + 127 * sinPreCalc(phase + 0.0f);
|
||||
uint8_t g = 127 + 127 * sinPreCalc(phase + 2.1f);
|
||||
uint8_t b = 127 + 127 * sinPreCalc(phase + 4.2f);
|
||||
return NeoPixel.Color(r, g, b);
|
||||
}
|
||||
|
||||
// Simple cat sprite (5x4)
|
||||
bool cat =
|
||||
(x == catX && y == catY) ||
|
||||
(x == catX + 1 && y == catY) ||
|
||||
(x == catX + 2 && y == catY) ||
|
||||
(x == catX + 3 && y == catY) ||
|
||||
|
||||
(x == catX && y == catY - 1) ||
|
||||
(x == catX + 1 && y == catY - 1) ||
|
||||
(x == catX + 2 && y == catY - 1) ||
|
||||
(x == catX + 3 && y == catY - 1) ||
|
||||
|
||||
(x == catX + 1 && y == catY - 2) ||
|
||||
(x == catX + 2 && y == catY - 2) ||
|
||||
|
||||
(x == catX + 1 && y == catY + 1) ||
|
||||
(x == catX + 2 && y == catY + 1);
|
||||
|
||||
if (cat) {
|
||||
return NeoPixel.Color(200, 180, 160); // cat body
|
||||
}
|
||||
|
||||
// Face pixels (eyes)
|
||||
if (x == catX + 1 && y == catY - 1) return NeoPixel.Color(0, 0, 0);
|
||||
if (x == catX + 2 && y == catY - 1) return NeoPixel.Color(0, 0, 0);
|
||||
|
||||
return bg;
|
||||
}
|
||||
|
||||
|
||||
uint32_t xwingDeathStarPixel(uint8_t x, uint8_t y, float timeMs) {
|
||||
// Convert ms to seconds for smooth trig
|
||||
float t = timeMs * 0.001f;
|
||||
|
||||
// Scene timing (ms)
|
||||
float flyTime = 2000.0f;
|
||||
float shootTime = 1200.0f;
|
||||
float explodeTime = 2000.0f;
|
||||
float total = flyTime + shootTime + explodeTime;
|
||||
|
||||
float local = fmod(timeMs, total);
|
||||
|
||||
// Positions
|
||||
int xwingX = (int)(-5 + (local / flyTime) * 30); // flies left -> right
|
||||
int xwingY = 10 + (int)(sinPreCalc(t * 2.0f) * 2.0f);
|
||||
|
||||
int dsX = 15;
|
||||
int dsY = 10;
|
||||
int dsR = 3;
|
||||
|
||||
// Background stars
|
||||
uint8_t bg = 10 + 10 * sinPreCalc(t * 0.5f + x * 0.7f + y * 0.3f);
|
||||
uint32_t color = NeoPixel.Color(0, 0, bg);
|
||||
|
||||
// Death Star body
|
||||
float dx = x - dsX;
|
||||
float dy = y - dsY;
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
bool onDeathStar = dist <= dsR;
|
||||
|
||||
// Phase 1: Fly-by
|
||||
if (local < flyTime) {
|
||||
if (onDeathStar) {
|
||||
return NeoPixel.Color(120, 120, 120); // gray Death Star
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Shooting
|
||||
if (local >= flyTime && local < flyTime + shootTime) {
|
||||
if (onDeathStar) {
|
||||
return NeoPixel.Color(150, 150, 150);
|
||||
}
|
||||
|
||||
// Laser beam
|
||||
int laserY = xwingY;
|
||||
if (y == laserY && x > xwingX && x < dsX) {
|
||||
return NeoPixel.Color(255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 3: Explosion
|
||||
if (local >= flyTime + shootTime) {
|
||||
float e = local - flyTime - shootTime;
|
||||
float radius = e * 0.005f;
|
||||
|
||||
if (dist < radius) {
|
||||
uint8_t r = 255;
|
||||
uint8_t g = max(0, 200 - (int)(e * 0.1f));
|
||||
uint8_t b = 0;
|
||||
return NeoPixel.Color(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
// X-Wing sprite (tiny cross)
|
||||
bool xwing =
|
||||
(x == xwingX && y == xwingY) ||
|
||||
(x == xwingX - 1 && y == xwingY) ||
|
||||
(x == xwingX + 1 && y == xwingY) ||
|
||||
(x == xwingX && y == xwingY - 1) ||
|
||||
(x == xwingX && y == xwingY + 1);
|
||||
|
||||
if (xwing) {
|
||||
return NeoPixel.Color(200, 200, 200);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
uint32_t flappyBirdPixel(uint8_t x, uint8_t y, float t) {
|
||||
const int W = 20;
|
||||
const int H = 20;
|
||||
|
||||
float time = 0.0;
|
||||
time = t / 400;
|
||||
// Bird position (fixed X, smooth Y motion)
|
||||
int birdX = 5;
|
||||
float birdY = 10.0f + sinPreCalc(time * 3.0f) * 3.0f; // flap motion
|
||||
|
||||
// Pipe movement (smooth scrolling)
|
||||
float pipePos = 19.0f - fmod(time * 4.0f, 25.0f);
|
||||
int pipeX = (int)pipePos;
|
||||
|
||||
// Moving gap
|
||||
float gapCenter = 10.0f + sinPreCalc(time * 0.7f) * 4.0f;
|
||||
int gapSize = 5;
|
||||
|
||||
// Background (sky)
|
||||
uint8_t bgR = 0, bgG = 0, bgB = 20;
|
||||
|
||||
// Pipes
|
||||
bool isPipe = (x == pipeX || x == pipeX - 1);
|
||||
bool inGap = (y >= gapCenter - gapSize / 2.0f &&
|
||||
y <= gapCenter + gapSize / 2.0f);
|
||||
|
||||
if (isPipe && !inGap) {
|
||||
return NeoPixel.Color(0, 160, 0);
|
||||
}
|
||||
|
||||
// Bird (2x2)
|
||||
bool isBird =
|
||||
(x == birdX || x == birdX + 1) &&
|
||||
(y == (int)birdY || y == (int)(birdY + 1));
|
||||
|
||||
if (isBird) {
|
||||
return NeoPixel.Color(255, 220, 0);
|
||||
}
|
||||
|
||||
return NeoPixel.Color(bgR, bgG, bgB);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t creeper(uint8_t x, uint8_t y, uint32_t timestep) {
|
||||
int phase = (timestep / 40) % 120; // animation cycle
|
||||
int cx = 10;
|
||||
int cy = 10;
|
||||
|
||||
// Base color = off
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
|
||||
// Creeper face mask
|
||||
bool face = false;
|
||||
bool eyeL = (x >= 5 && x <= 7 && y >= 5 && y <= 7);
|
||||
bool eyeR = (x >= 12 && x <= 14 && y >= 5 && y <= 7);
|
||||
bool mouth =
|
||||
((x >= 7 && x <= 12 && y >= 11 && y <= 13) ||
|
||||
(x >= 8 && x <= 9 && y >= 9 && y <= 11) ||
|
||||
(x >= 10 && x <= 11 && y >= 9 && y <= 11));
|
||||
|
||||
bool head = (x >= 3 && x <= 16 && y >= 3 && y <= 16);
|
||||
|
||||
// Phase 1 – Normal creeper
|
||||
if (phase < 50) {
|
||||
if (head) {
|
||||
if (eyeL || eyeR || mouth) {
|
||||
return NeoPixel.Color(0, 0, 0);
|
||||
} else {
|
||||
return NeoPixel.Color(0, 180, 0);
|
||||
}
|
||||
}
|
||||
return NeoPixel.Color(0, 0, 0);
|
||||
}
|
||||
|
||||
// Phase 2 – White flash (about to explode)
|
||||
if (phase < 65) {
|
||||
if (head) {
|
||||
uint8_t flash = 200 + 55 * sinPreCalc(phase * 0.8);
|
||||
return NeoPixel.Color(flash, flash, flash);
|
||||
}
|
||||
return NeoPixel.Color(0, 0, 0);
|
||||
}
|
||||
|
||||
// Phase 3 – Explosion
|
||||
int t = phase - 65;
|
||||
float dx = x - cx;
|
||||
float dy = y - cy;
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Expanding explosion radius
|
||||
float radius = t * 0.4;
|
||||
|
||||
if (dist > radius && dist < radius + 2) {
|
||||
// fiery ring
|
||||
uint8_t rr = 255;
|
||||
uint8_t gg = random(80, 160);
|
||||
return NeoPixel.Color(rr, gg, 0);
|
||||
}
|
||||
|
||||
if (dist < radius) {
|
||||
// fading embers
|
||||
uint8_t fade = max(0, 200 - t * 6);
|
||||
return NeoPixel.Color(fade, fade / 2, 0);
|
||||
}
|
||||
|
||||
return NeoPixel.Color(0, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t breathe(uint8_t x, uint8_t y, float t) {
|
||||
float cx = 9.5, cy = 9.5;
|
||||
float dx = x - cx;
|
||||
float dy = y - cy;
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
float wave = sinPreCalc(dist * 0.6 - t * 0.05 / 200.0);
|
||||
float breath = (sinPreCalc(t * 0.02 / 200.0) + 1) * 0.5;
|
||||
|
||||
uint8_t r = 50 + 200 * breath;
|
||||
uint8_t g = 30 + 100 * wave * breath;
|
||||
uint8_t b = 150 + 100 * (1 - breath);
|
||||
|
||||
return NeoPixel.Color(r, g, b);
|
||||
}
|
||||
|
||||
uint32_t galaxy(uint8_t x, uint8_t y, float t) {
|
||||
float cx = 9.5, cy = 9.5;
|
||||
float dx = x - cx;
|
||||
float dy = y - cy;
|
||||
float angle = atan2(dy, dx);
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
float spin = angle + dist * 0.3 - t / 10 * 0.02;
|
||||
float v = (sinPreCalc(spin * 3) + 1) * 0.5;
|
||||
|
||||
uint8_t r = 80 + 175 * v;
|
||||
uint8_t g = 0;
|
||||
uint8_t b = 120 + 135 * (1 - v);
|
||||
|
||||
return NeoPixel.Color(r, g, b);
|
||||
}
|
||||
|
||||
float distToSegment(float px, float py, float x1, float y1, float x2, float y2) {
|
||||
float vx = x2 - x1;
|
||||
float vy = y2 - y1;
|
||||
float wx = px - x1;
|
||||
float wy = py - y1;
|
||||
|
||||
float c1 = vx * wx + vy * wy;
|
||||
if (c1 <= 0) return sqrt((px - x1)*(px - x1) + (py - y1)*(py - y1));
|
||||
|
||||
float c2 = vx * vx + vy * vy;
|
||||
if (c2 <= c1) return sqrt((px - x2)*(px - x2) + (py - y2)*(py - y2));
|
||||
|
||||
float b = c1 / c2;
|
||||
float bx = x1 + b * vx;
|
||||
float by = y1 + b * vy;
|
||||
|
||||
return sqrt((px - bx)*(px - bx) + (py - by)*(py - by));
|
||||
}
|
||||
|
||||
uint32_t flyingWireCubeHard(uint8_t x, uint8_t y, float t) {
|
||||
float cx = 9.5;
|
||||
float cy = 9.5;
|
||||
|
||||
float time = t * 0.0015 / 2.0;
|
||||
|
||||
float cube[8][3] = {
|
||||
{-1,-1,-1}, {1,-1,-1}, {1,1,-1}, {-1,1,-1},
|
||||
{-1,-1, 1}, {1,-1, 1}, {1,1, 1}, {-1,1, 1}
|
||||
};
|
||||
|
||||
const uint8_t edges[12][2] = {
|
||||
{0,1},{1,2},{2,3},{3,0},
|
||||
{4,5},{5,6},{6,7},{7,4},
|
||||
{0,4},{1,5},{2,6},{3,7}
|
||||
};
|
||||
|
||||
float zpos = fmod(time * 3.0, 6.0) + 2.0;
|
||||
float scale = 7.0;
|
||||
|
||||
float rx = time * 1.3;
|
||||
float ry = time * 0.9;
|
||||
float rz = time * 0.7;
|
||||
|
||||
float px = x;
|
||||
float py = y;
|
||||
|
||||
float proj[8][2];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float X = cube[i][0];
|
||||
float Y = cube[i][1];
|
||||
float Z = cube[i][2];
|
||||
|
||||
float y1 = Y * sinPreCalc(TWO_PI/4 - rx) - Z * sinPreCalc(rx);
|
||||
float z1 = Y * sinPreCalc(rx) + Z * sinPreCalc(TWO_PI/4 - rx);
|
||||
Y = y1; Z = z1;
|
||||
|
||||
float x2 = X * sinPreCalc(TWO_PI/4 - ry) + Z * sinPreCalc(ry);
|
||||
float z2 = -X * sinPreCalc(ry) + Z * sinPreCalc(TWO_PI/4 - ry);
|
||||
X = x2; Z = z2;
|
||||
|
||||
float x3 = X * sinPreCalc(TWO_PI/4 - rz) - Y * sinPreCalc(rz);
|
||||
float y3 = X * sinPreCalc(rz) + Y * sinPreCalc(TWO_PI/4 - rz);
|
||||
X = x3; Y = y3;
|
||||
|
||||
proj[i][0] = cx + X * scale;
|
||||
proj[i][1] = cy + Y * scale;
|
||||
}
|
||||
|
||||
bool onEdge = false;
|
||||
const float thickness = 0.6; // edge thickness in pixels
|
||||
|
||||
for (int e = 0; e < 12; e++) {
|
||||
int a = edges[e][0];
|
||||
int b = edges[e][1];
|
||||
|
||||
float d = distToSegment(px, py,
|
||||
proj[a][0], proj[a][1],
|
||||
proj[b][0], proj[b][1]);
|
||||
|
||||
if (d < thickness) {
|
||||
onEdge = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (onEdge) {
|
||||
return NeoPixel.Color(0, 0, 255); // sharp neon wireframe
|
||||
} else {
|
||||
return NeoPixel.Color(0, 0, 0); // background off
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isPacmanPixel(int px, int py, float cx, float cy, float r, float mouthOpen) {
|
||||
float dx = px - cx;
|
||||
float dy = py - cy;
|
||||
float dist2 = dx*dx + dy*dy;
|
||||
|
||||
if (dist2 > r*r) return false;
|
||||
|
||||
float angle = atan2(dy, dx); // -PI..PI
|
||||
|
||||
// Mouth opening angle
|
||||
float mouth = mouthOpen * 0.8; // max opening
|
||||
if (angle > -mouth && angle < mouth) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t pacman(uint8_t x, uint8_t y, uint32_t t) {
|
||||
// Movement
|
||||
float time = t * 0.005 / 3.0;
|
||||
float cx = fmod(time * 6.0, 26.0) - 3.0; // move across screen
|
||||
float cy = 10.0;
|
||||
float r = 4.0;
|
||||
|
||||
// Mouth animation (chomp)
|
||||
float mouth = (sinPreCalc(time * 6.0) + 1.0) * 0.5; // 0..1
|
||||
|
||||
// Optional pellets
|
||||
int pelletX = ((int)(time * 6.0)) % 20;
|
||||
bool pellet = (x == pelletX && y == 10);
|
||||
|
||||
if (isPacmanPixel(x, y, cx, cy, r, mouth)) {
|
||||
return NeoPixel.Color(255, 220, 0); // Pac-Man yellow
|
||||
}
|
||||
|
||||
if (pellet) {
|
||||
return NeoPixel.Color(200, 200, 200); // pellet
|
||||
}
|
||||
|
||||
return NeoPixel.Color(0, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t coolEffect(uint8_t x, uint8_t y, float t) {
|
||||
// Center of the grid
|
||||
float cx = 9.5;
|
||||
float cy = 9.5;
|
||||
float time = 0;
|
||||
time = t / 100.0;
|
||||
|
||||
// Distance from center
|
||||
float dx = x - cx;
|
||||
float dy = y - cy;
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Animated wave
|
||||
float wave = sinPreCalc(dist * 0.6 - time * 0.15);
|
||||
|
||||
// Rainbow hue shifts over time and space
|
||||
float hue = dist * 20 + time * 3;
|
||||
|
||||
// Breathing brightness
|
||||
float brightness = (sinPreCalc(time * 0.08) + 1.0) * 0.5; // 0..1
|
||||
|
||||
// Convert HSV → RGB (simple version)
|
||||
uint8_t r, g, b;
|
||||
float h = fmod(hue, 360.0);
|
||||
|
||||
int i = int(h / 60.0) % 6;
|
||||
float f = (h / 60.0) - i;
|
||||
float v = brightness * (0.5 + 0.5 * wave);
|
||||
if (v < 0) v = 0;
|
||||
if (v > 1) v = 1;
|
||||
|
||||
float p = 0;
|
||||
float q = v * (1 - f);
|
||||
float s = v * f;
|
||||
|
||||
float R, G, B;
|
||||
switch (i) {
|
||||
case 0: R = v; G = s; B = p; break;
|
||||
case 1: R = q; G = v; B = p; break;
|
||||
case 2: R = p; G = v; B = s; break;
|
||||
case 3: R = p; G = q; B = v; break;
|
||||
case 4: R = s; G = p; B = v; break;
|
||||
default: R = v; G = p; B = q; break;
|
||||
}
|
||||
|
||||
r = (uint8_t)(R * 255);
|
||||
g = (uint8_t)(G * 255);
|
||||
b = (uint8_t)(B * 255);
|
||||
|
||||
return NeoPixel.Color(r, g, b);
|
||||
}
|
||||
Reference in New Issue
Block a user