фигасеее… да мы тут не мой код от ии, а ваш код облагораживаем, и вы его почти сами сделали…
выводить часть изображения и дорисовывать остальные части это вообще нечто)))
как и в маленьком коде заложить столько разных фигур…
#include <TFT_eSPI.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();
// ==== РАЗМЕРЫ ====
#define CENTER_X 64
#define CENTER_Y 80
#define MAX_RADIUS 60
#define NUM_SEGMENTS 6
#define MAX_POINTS 15
struct SnowPoint {
float r; // радиус
float angle; // угол в радианах (0-PI/6)
};
SnowPoint points[MAX_POINTS];
int pointCount = 0;
float currentRadius = 5;
int growthDirection = 1;
unsigned long lastTime = 0;
const int animationDelay = 120;
void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
#ifdef TFT_BL
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
#endif
}
// ЗЕЛЕНЫЕ ЦВЕТА
uint16_t getSnowColor(float radius) {
float ratio = radius / MAX_RADIUS;
if (ratio < 0.3) return TFT_WHITE;
if (ratio < 0.6) return tft.color565(180, 255, 180); // Светло-зеленый
if (ratio < 0.8) return tft.color565(100, 220, 100); // Зеленый
return tft.color565(50, 180, 50); // Темно-зеленый
}
// Функция для линии
void drawLine(int x0, int y0, int x1, int y1, uint16_t color) {
tft.drawLine(x0, y0, x1, y1, color);
}
// Функция для полярных координат
void drawPolarLine(float r1, float a1, float r2, float a2, uint16_t color) {
int x1 = CENTER_X + (int)(r1 * cos(a1));
int y1 = CENTER_Y + (int)(r1 * sin(a1));
int x2 = CENTER_X + (int)(r2 * cos(a2));
int y2 = CENTER_Y + (int)(r2 * sin(a2));
drawLine(x1, y1, x2, y2, color);
}
// Создание сложной точки снежинки
void addSnowPoint() {
if (pointCount >= MAX_POINTS) {
// Начинаем новую снежинку
pointCount = 0;
tft.fillScreen(TFT_BLACK);
currentRadius = 5;
return;
}
float baseAngle;
if (pointCount == 0) {
// Первая точка - старт из центра
baseAngle = random(5, 26) * PI / 180.0; // 5-25 градусов
} else {
// Продолжаем линию с изгибом
float prevAngle = points[pointCount-1].angle;
// Чем дальше от центра, тем больше изгиб
float curvature = 0.5 + (pointCount / (float)MAX_POINTS) * 2.0;
int angleChange = random(-10, 11) * curvature;
baseAngle = prevAngle + angleChange * PI / 180.0;
baseAngle = constrain(baseAngle, 0, PI/6);
}
// Радиус плавно увеличивается
float r;
if (pointCount == 0) {
r = 3; // Начинаем почти из центра
} else {
r = currentRadius * (0.1 + 0.9 * (pointCount / (float)MAX_POINTS));
}
points[pointCount].r = r;
points[pointCount].angle = baseAngle;
pointCount++;
}
// Удаление последней точки
void removeLastPoint() {
if (pointCount > 0) {
pointCount--;
}
}
// Рисование снежинки (без центрального круга и линий!)
void drawPureSnowflake() {
// Полная очистка
tft.fillScreen(TFT_BLACK);
// Если точек меньше 2, рисуем только первую точку в центре
if (pointCount == 1) {
// Маленькая белая точка в центре
tft.drawPixel(CENTER_X, CENTER_Y, TFT_WHITE);
return;
}
if (pointCount < 2) return;
// Рисуем основную структуру снежинки
for (int i = 1; i < pointCount; i++) {
SnowPoint p1 = points[i-1];
SnowPoint p2 = points[i];
// Для первой линии рисуем от центра
if (i == 1) {
p1.r = 0; // Начинаем из центра
}
uint16_t color = getSnowColor((p1.r + p2.r) / 2);
// 6-кратная симметрия
for (int sector = 0; sector < NUM_SEGMENTS; sector++) {
float rotation = sector * (2 * PI / NUM_SEGMENTS);
// Основная ветвь
drawPolarLine(p1.r, p1.angle + rotation,
p2.r, p2.angle + rotation,
color);
// Зеркальная ветвь
drawPolarLine(p1.r, -p1.angle + rotation,
p2.r, -p2.angle + rotation,
color);
}
}
// Добавляем боковые веточки
if (pointCount > 3) {
drawSideBranches();
}
// Добавляем кончики
if (pointCount > 0) {
drawSnowflakeTips();
}
}
// Боковые веточки на основных ветвях
void drawSideBranches() {
// Добавляем веточки на каждую 3-ю точку
for (int i = 2; i < pointCount; i += 3) {
SnowPoint p = points[i];
if (p.r > MAX_RADIUS * 0.3) {
uint16_t branchColor = getSnowColor(p.r * 0.8);
for (int sector = 0; sector < NUM_SEGMENTS; sector++) {
float rotation = sector * (2 * PI / NUM_SEGMENTS);
// Координаты точки на основной ветви
int x0 = CENTER_X + (int)(p.r * cos(p.angle + rotation));
int y0 = CENTER_Y + (int)(p.r * sin(p.angle + rotation));
// Две боковые веточки
for (int side = -1; side <= 1; side += 2) {
float branchAngle = p.angle + rotation + side * 45 * PI / 180.0;
float branchLength = p.r * 0.3;
int x1 = x0 + (int)(branchLength * cos(branchAngle));
int y1 = y0 + (int)(branchLength * sin(branchAngle));
drawLine(x0, y0, x1, y1, branchColor);
// Маленькие ответвления на боковых веточках
if (p.r > MAX_RADIUS * 0.5) {
float subAngle = branchAngle + side * 30 * PI / 180.0;
float subLength = branchLength * 0.5;
int x2 = x1 + (int)(subLength * cos(subAngle));
int y2 = y1 + (int)(subLength * sin(subAngle));
drawLine(x1, y1, x2, y2, branchColor);
}
}
}
// Также для зеркальных ветвей
for (int sector = 0; sector < NUM_SEGMENTS; sector++) {
float rotation = sector * (2 * PI / NUM_SEGMENTS);
int x0 = CENTER_X + (int)(p.r * cos(-p.angle + rotation));
int y0 = CENTER_Y + (int)(p.r * sin(-p.angle + rotation));
for (int side = -1; side <= 1; side += 2) {
float branchAngle = -p.angle + rotation + side * 45 * PI / 180.0;
float branchLength = p.r * 0.3;
int x1 = x0 + (int)(branchLength * cos(branchAngle));
int y1 = y0 + (int)(branchLength * sin(branchAngle));
drawLine(x0, y0, x1, y1, branchColor);
}
}
}
}
}
// Кончики снежинки
void drawSnowflakeTips() {
if (pointCount == 0) return;
SnowPoint lastPoint = points[pointCount-1];
if (lastPoint.r > MAX_RADIUS * 0.4) {
uint16_t tipColor = TFT_WHITE;
for (int sector = 0; sector < NUM_SEGMENTS; sector++) {
float rotation = sector * (2 * PI / NUM_SEGMENTS);
// Кончики для основных ветвей
float angles[2] = {lastPoint.angle + rotation, -lastPoint.angle + rotation};
for (int a = 0; a < 2; a++) {
float angle = angles[a];
int x0 = CENTER_X + (int)(lastPoint.r * cos(angle));
int y0 = CENTER_Y + (int)(lastPoint.r * sin(angle));
// Три луча на кончике
for (int i = 0; i < 3; i++) {
float tipAngle = angle + (i * 120 - 60) * PI / 180.0;
float tipLength = lastPoint.r * 0.15;
int x1 = x0 + (int)(tipLength * cos(tipAngle));
int y1 = y0 + (int)(tipLength * sin(tipAngle));
drawLine(x0, y0, x1, y1, tipColor);
}
}
}
}
}
void loop() {
if (millis() - lastTime > animationDelay) {
lastTime = millis();
// Изменение радиуса
currentRadius += growthDirection * 0.7;
// Реверс направления
if (currentRadius >= MAX_RADIUS) {
currentRadius = MAX_RADIUS;
growthDirection = -1;
} else if (currentRadius <= 5) {
currentRadius = 5;
growthDirection = 1;
pointCount = 0;
tft.fillScreen(TFT_BLACK);
return;
}
// Управление точками
if (growthDirection > 0) {
addSnowPoint();
} else {
if (random(100) < 25) {
removeLastPoint();
}
}
// Рисуем чистую снежинку
drawPureSnowflake();
}
}
если все быстро не так и заметно))) если еще озу есть, можно сделать более плавный вывод… все равно это лучше чем то что у меня получалось)))
еще можно попытаться просто увеличивать изображение кстате…. и будет и рост и снежинка вроде как…
вам вот такая простая снежинка не подойдет ?)))
#include <TFT_eSPI.h>
#include <SPI.h>
#include <math.h>
TFT_eSPI tft = TFT_eSPI();
#define CENTER_X 80
#define CENTER_Y 80
#define MAX_RADIUS 45
#define PI 3.14159265359
#define BRANCHES 6
float growth = 0.0;
float growthSpeed = 0.004;
unsigned long lastTime = 0;
const int FRAME_DELAY = 30;
float lastDrawnGrowth = -1.0;
int lastClearRadius = 0;
void setup() {
tft.init();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
#ifdef TFT_BL
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
#endif
}
uint16_t getSnowColor(float distance) {
float ratio = distance / MAX_RADIUS;
if (ratio < 0.3) return TFT_WHITE;
if (ratio < 0.5) return tft.color565(220, 240, 255);
if (ratio < 0.7) return tft.color565(180, 220, 250);
return tft.color565(140, 200, 240);
}
void clearSnowflakeArea(float currentGrowth) {
int clearRadius = (int)(MAX_RADIUS * currentGrowth) + 10;
if (clearRadius > lastClearRadius || clearRadius < lastClearRadius - 5) {
int clearSize = clearRadius * 2 + 5;
int startX = CENTER_X - clearSize/2;
int startY = CENTER_Y - clearSize/2;
startX = max(0, startX);
startY = max(0, startY);
clearSize = min(clearSize, min(128 - startX, 160 - startY));
tft.fillRect(startX, startY, clearSize, clearSize, TFT_BLACK);
lastClearRadius = clearRadius;
}
}
void drawBranch(float angle, float growthFactor) {
if (growthFactor < 0.05) return;
float length = MAX_RADIUS * growthFactor;
if (length < 2) return;
int x1 = CENTER_X + length * cos(angle);
int y1 = CENTER_Y + length * sin(angle);
uint16_t color = getSnowColor(length);
tft.drawLine(CENTER_X, CENTER_Y, x1, y1, color);
if (growthFactor > 0.35 && length > 10) {
float mid1 = length * 0.33;
int mx1 = CENTER_X + mid1 * cos(angle);
int my1 = CENTER_Y + mid1 * sin(angle);
for (int side = -1; side <= 1; side += 2) {
float sideAngle = angle + side * PI / 4.0;
float sideLen = length * 0.25;
int sx1 = mx1 + sideLen * cos(sideAngle);
int sy1 = my1 + sideLen * sin(sideAngle);
tft.drawLine(mx1, my1, sx1, sy1, color);
}
if (growthFactor > 0.65) {
float mid2 = length * 0.66;
int mx2 = CENTER_X + mid2 * cos(angle);
int my2 = CENTER_Y + mid2 * sin(angle);
for (int side = -1; side <= 1; side += 2) {
float sideAngle = angle + side * PI / 3.0;
float sideLen = length * 0.2;
int sx2 = mx2 + sideLen * cos(sideAngle);
int sy2 = my2 + sideLen * sin(sideAngle);
tft.drawLine(mx2, my2, sx2, sy2, color);
}
}
}
if (growthFactor > 0.85 && length > 20) {
drawTip(x1, y1, angle, length * 0.12);
}
}
void drawTip(int x, int y, float angle, float size) {
if (size < 2) return;
uint16_t tipColor = tft.color565(255, 255, 240);
for (int i = 0; i < 3; i++) {
float tipAngle = angle + (i * 120 - 60) * PI / 180.0;
int x1 = x + size * cos(tipAngle);
int y1 = y + size * sin(tipAngle);
tft.drawLine(x, y, x1, y1, tipColor);
}
}
void drawCenter(float growthFactor) {
if (growthFactor < 0.05) return;
tft.fillCircle(CENTER_X, CENTER_Y, 15, TFT_BLACK);
int centerSize = 1 + (int)(growthFactor * 3);
tft.fillCircle(CENTER_X, CENTER_Y, centerSize, TFT_WHITE);
if (growthFactor > 0.15) {
int rayLength = 4 + (int)(growthFactor * 6);
for (int i = 0; i < BRANCHES; i++) {
float angle = i * 2 * PI / BRANCHES;
int x = CENTER_X + rayLength * cos(angle);
int y = CENTER_Y + rayLength * sin(angle);
tft.drawLine(CENTER_X, CENTER_Y, x, y, tft.color565(200, 230, 255));
}
}
if (growthFactor > 0.45) {
tft.drawCircle(CENTER_X, CENTER_Y, 8, tft.color565(180, 210, 240));
}
}
void drawConnections(float growthFactor) {
if (growthFactor < 0.9) return;
uint16_t color = tft.color565(160, 200, 235);
float radius = MAX_RADIUS * 0.6;
for (int i = 0; i < BRANCHES; i += 2) {
int next = (i + 2) % BRANCHES;
float angle1 = i * 2 * PI / BRANCHES;
float angle2 = next * 2 * PI / BRANCHES;
int x1 = CENTER_X + radius * cos(angle1);
int y1 = CENTER_Y + radius * sin(angle1);
int x2 = CENTER_X + radius * cos(angle2);
int y2 = CENTER_Y + radius * sin(angle2);
tft.drawLine(x1, y1, x2, y2, color);
}
}
void drawSnowflake(float currentGrowth) {
clearSnowflakeArea(currentGrowth);
drawCenter(currentGrowth);
for (int i = 0; i < BRANCHES; i++) {
float angle = i * 2 * PI / BRANCHES;
drawBranch(angle, currentGrowth);
}
drawConnections(currentGrowth);
lastDrawnGrowth = currentGrowth;
}
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastTime >= FRAME_DELAY) {
lastTime = currentTime;
growth += growthSpeed;
if (growth >= 1.0) {
growth = 1.0;
static unsigned long pauseStart = 0;
if (pauseStart == 0) pauseStart = currentTime;
if (currentTime - pauseStart > 2000) {
growthSpeed = -0.004;
pauseStart = 0;
}
} else if (growth <= 0.0) {
growth = 0.0;
growthSpeed = 0.004;
lastClearRadius = 0;
lastDrawnGrowth = -1.0;
}
if (abs(growth - lastDrawnGrowth) > 0.001) {
drawSnowflake(growth);
}
}
}
https://ru.files.me/u/p29ne2nvf4
если не везде обновлять изображение, еще может получится шлейф от нее…
а вообще в математики и снежинки лишняя снежинка))) может впихнуть туда золотой сечение фибоначи ? и будет совершенная математическая снежинка))) только не похожая на настоящую, в любом случае может это натолкнет вас на какие то мысли, и вы сделаете какую то свою)))