#include <Adafruit_NeoPixel.h>
#define PIN 15 // Pin do którego podłączona jest matryca
#define WIDTH 16 // Szerokość matrycy
#define HEIGHT 16 // Wysokość matrycy
#define NUMPIXELS (WIDTH * HEIGHT)
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// Mapowanie współrzędnych (Z-shape)
int getPixelIndex(int x, int y) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) return -1;
return (y % 2 == 0) ? y * WIDTH + x : y * WIDTH + (WIDTH - 1 - x);
}
#define PANORAMA_WIDTH 64 // Szerokość przesuwanej panoramy
uint32_t colors[PANORAMA_WIDTH][HEIGHT];
int offset = 0; // Pozycja przesunięcia panoramy
// Samochód
int carX = -4;
const int carWidth = 3;
const int carY = HEIGHT - 3;
int loopCounter = 0;
bool carVisible = false;
// Tryb dzień/noc
bool nightMode = false;
int nightTransitionCounter = 0;
bool panoramaGenerated = false;
// Rysowanie samochodu na ekranie
void drawCar() {
if (!carVisible) return;
// Górna część samochodu
for (int dx = 0; dx < 2; dx++) {
int x = carX + dx;
if (x >= 0 && x < WIDTH) {
strip.setPixelColor(getPixelIndex(x, carY), strip.Color(255, 0, 0));
}
}
// Dolna część samochodu
for (int dx = 0; dx < carWidth; dx++) {
int x = carX + dx;
if (x >= 0 && x < WIDTH) {
strip.setPixelColor(getPixelIndex(x, carY + 1), strip.Color(255, 0, 0));
}
}
// Koła samochodu
int wheelY = carY + 2;
int leftWheelX = carX;
int rightWheelX = carX + carWidth - 1;
if (leftWheelX >= 0 && leftWheelX < WIDTH)
strip.setPixelColor(getPixelIndex(leftWheelX, wheelY), strip.Color(0, 0, 0));
if (rightWheelX >= 0 && rightWheelX < WIDTH)
strip.setPixelColor(getPixelIndex(rightWheelX, wheelY), strip.Color(0, 0, 0));
}
// Generowanie panoramy (tło, budynki, drzewa, gwiazdy itp.)
void generatePanorama() {
uint32_t skyColor = nightMode ? strip.Color(0, 0, 40) : strip.Color(100, 150, 255);
uint32_t cloudColor = strip.Color(255, 255, 255);
// Wypełnienie tła kolorem nieba
for (int x = 0; x < PANORAMA_WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
colors[x][y] = skyColor;
}
}
// Rysowanie chmur w dzień
if (!nightMode) {
int cloudCount = random(3, 6);
for (int i = 0; i < cloudCount; i++) {
int cx = random(1, PANORAMA_WIDTH - 5);
int cy = random(0, 3);
for (int dx = -2; dx <= 1; dx++) {
int x = cx + dx;
int y = cy + 1;
if (x >= 0 && x < PANORAMA_WIDTH && y < HEIGHT) {
colors[x][y] = cloudColor;
}
}
for (int dx = -1; dx <= 0; dx++) {
int x = cx + dx;
int y = cy;
if (x >= 0 && x < PANORAMA_WIDTH && y < HEIGHT) {
colors[x][y] = cloudColor;
}
}
}
}
// Rysowanie gwiazd w nocy
if (nightMode) {
int starCount = random(10, 20);
for (int i = 0; i < starCount; i++) {
int x = random(0, PANORAMA_WIDTH);
int y = random(0, 5);
colors[x][y] = strip.Color(255, 255, 0);
}
}
// Budynki i drzewa
int x = 0;
while (x < PANORAMA_WIDTH) {
int choice = random(0, 5);
if (choice < 3) {
// Budynek
int buildingWidth = random(2, 5);
int buildingHeight = random(6, 14);
int top = HEIGHT - buildingHeight;
for (int i = 0; i < buildingWidth && (x + i) < PANORAMA_WIDTH; i++) {
for (int y = top; y < HEIGHT; y++) {
colors[x + i][y] = strip.Color(80, 80, 80);
}
}
x += buildingWidth + random(1, 2);
} else {
// Drzewo
int trunkX = x;
int trunkHeight = random(1, 4);
int trunkBottomY = HEIGHT - 1;
// Pień drzewa
for (int i = 0; i < trunkHeight; i++) {
int y = trunkBottomY - i;
if (y >= 0) {
colors[trunkX][y] = strip.Color(139, 69, 19);
}
}
// Korona drzewa (2x3 + 1 piksel na górze)
int crownHeight = 2;
int crownWidth = 3;
int crownTopY = trunkBottomY - trunkHeight - (crownHeight - 1);
for (int dx = -1; dx <= 1; dx++) {
for (int dy = 0; dy < 2; dy++) {
int cx = trunkX + dx;
int cy = crownTopY + dy;
if (cx >= 0 && cx < PANORAMA_WIDTH && cy >= 0 && cy < HEIGHT) {
colors[cx][cy] = strip.Color(0, 200 + random(0, 56), 0);
}
}
}
int topCenterX = trunkX;
int topCenterY = crownTopY - 1;
if (topCenterX >= 0 && topCenterX < PANORAMA_WIDTH && topCenterY >= 0 && topCenterY < HEIGHT) {
colors[topCenterX][topCenterY] = strip.Color(0, 200 + random(0, 56), 0);
}
x += crownWidth + 1;
}
}
}
// Wyświetlenie aktualnej klatki panoramy
void drawFrame() {
strip.clear();
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
int panoX = (x + offset) % PANORAMA_WIDTH; // Obliczenie pozycji X w panoramie (przesuwane tło)
strip.setPixelColor(getPixelIndex(x, y), colors[panoX][y]);
}
}
}
void setup() {
strip.begin();
strip.setBrightness(100);
strip.show();
generatePanorama();
panoramaGenerated = true;
}
void loop() {
drawFrame();
drawCar();
strip.show();
// Przesunięcie panoramy
offset++;
if (offset >= PANORAMA_WIDTH) {
offset = 0;
}
// Obsługa samochodu
loopCounter++;
if (loopCounter % 64 == 0) {
carX = -carWidth;
carVisible = true;
}
if (carVisible) {
carX++;
if (carX > WIDTH + carWidth) {
carVisible = false;
}
}
// Przełączanie dnia i nocy co 200 pętli
nightTransitionCounter++;
if (nightTransitionCounter >= 200) {
nightTransitionCounter = 0;
nightMode = !nightMode;
generatePanorama();
}