很好的LED显示例子

[复制链接]
 楼主| keer_zu 发表于 2025-5-21 12:15 | 显示全部楼层 |阅读模式
代码:

  1. // TETRIS
  2. #include <FastLED.h>
  3. #include <LEDMatrix.h>
  4. #include <LEDSprites.h>
  5. #include <LEDText.h>
  6. #include <FontMatrise.h>
  7. #include "BluetoothSerial.h"

  8. #define LED_PIN        15
  9. #define COLOR_ORDER    GRB
  10. #define CHIPSET        WS2812B
  11. #define MATRIX_WIDTH   30
  12. #define MATRIX_HEIGHT  15
  13. #define MATRIX_TYPE    HORIZONTAL_MATRIX

  14. // NOTE the '-' sign before the width, this is due to my leds matrix origin being on the right hand side
  15. cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;

  16. BluetoothSerial SerialBT;

  17. #define TARGET_FRAME_TIME    15  // Desired update rate, though if too many leds it will just run as fast as it can!
  18. #define INITIAL_DROP_FRAMES  20  // Start of game block drop delay in frames

  19. // Bluetooth input
  20. enum btnInput {NONE, ROTATE, DOWN, LEFT, RIGHT};
  21. btnInput currentInput = NONE;

  22. const uint8_t TetrisIData[] =
  23. {
  24.   // Frame 1
  25.   B8_3BIT(00000000),
  26.   B8_3BIT(00000000),
  27.   B8_3BIT(00000000),
  28.   B8_3BIT(11110000),
  29.   // Frame 2
  30.   B8_3BIT(10000000),
  31.   B8_3BIT(10000000),
  32.   B8_3BIT(10000000),
  33.   B8_3BIT(10000000),
  34.   // Frame 3
  35.   B8_3BIT(00000000),
  36.   B8_3BIT(00000000),
  37.   B8_3BIT(00000000),
  38.   B8_3BIT(11110000),
  39.   // Frame 4
  40.   B8_3BIT(10000000),
  41.   B8_3BIT(10000000),
  42.   B8_3BIT(10000000),
  43.   B8_3BIT(10000000)
  44. };
  45. const uint8_t TetrisIMask[] =
  46. {
  47.   // Frame 1
  48.   B8_1BIT(00000000),
  49.   B8_1BIT(00000000),
  50.   B8_1BIT(00000000),
  51.   B8_1BIT(11110000),
  52.   // Frame 2
  53.   B8_1BIT(10000000),
  54.   B8_1BIT(10000000),
  55.   B8_1BIT(10000000),
  56.   B8_1BIT(10000000),
  57.   // Frame 3
  58.   B8_1BIT(00000000),
  59.   B8_1BIT(00000000),
  60.   B8_1BIT(00000000),
  61.   B8_1BIT(11110000),
  62.   // Frame 4
  63.   B8_1BIT(10000000),
  64.   B8_1BIT(10000000),
  65.   B8_1BIT(10000000),
  66.   B8_1BIT(10000000)
  67. };
  68. const uint8_t TetrisJData[] =
  69. {
  70.   // Frame 1
  71.   B8_3BIT(00000000),
  72.   B8_3BIT(00000000),
  73.   B8_3BIT(22200000),
  74.   B8_3BIT(00200000),
  75.   // Frame 2
  76.   B8_3BIT(00000000),
  77.   B8_3BIT(02000000),
  78.   B8_3BIT(02000000),
  79.   B8_3BIT(22000000),
  80.   // Frame 3
  81.   B8_3BIT(00000000),
  82.   B8_3BIT(00000000),
  83.   B8_3BIT(20000000),
  84.   B8_3BIT(22200000),
  85.   // Frame 4
  86.   B8_3BIT(00000000),
  87.   B8_3BIT(22000000),
  88.   B8_3BIT(20000000),
  89.   B8_3BIT(20000000)
  90. };
  91. const uint8_t TetrisJMask[] =
  92. {
  93.   // Frame 1
  94.   B8_1BIT(00000000),
  95.   B8_1BIT(00000000),
  96.   B8_1BIT(11100000),
  97.   B8_1BIT(00100000),
  98.   // Frame 2
  99.   B8_1BIT(00000000),
  100.   B8_1BIT(01000000),
  101.   B8_1BIT(01000000),
  102.   B8_1BIT(11000000),
  103.   // Frame 3
  104.   B8_1BIT(00000000),
  105.   B8_1BIT(00000000),
  106.   B8_1BIT(10000000),
  107.   B8_1BIT(11100000),
  108.   // Frame 4
  109.   B8_1BIT(00000000),
  110.   B8_1BIT(11000000),
  111.   B8_1BIT(10000000),
  112.   B8_1BIT(10000000)
  113. };
  114. const uint8_t TetrisLData[] =
  115. {
  116.   // Frame 1
  117.   B8_3BIT(00000000),
  118.   B8_3BIT(00000000),
  119.   B8_3BIT(33300000),
  120.   B8_3BIT(30000000),
  121.   // Frame 2
  122.   B8_3BIT(00000000),
  123.   B8_3BIT(33000000),
  124.   B8_3BIT(03000000),
  125.   B8_3BIT(03000000),
  126.   // Frame 3
  127.   B8_3BIT(00000000),
  128.   B8_3BIT(00000000),
  129.   B8_3BIT(00300000),
  130.   B8_3BIT(33300000),
  131.   // Frame 4
  132.   B8_3BIT(00000000),
  133.   B8_3BIT(30000000),
  134.   B8_3BIT(30000000),
  135.   B8_3BIT(33000000)
  136. };
  137. const uint8_t TetrisLMask[] =
  138. {
  139.   // Frame 1
  140.   B8_1BIT(00000000),
  141.   B8_1BIT(00000000),
  142.   B8_1BIT(11100000),
  143.   B8_1BIT(10000000),
  144.   // Frame 2
  145.   B8_1BIT(00000000),
  146.   B8_1BIT(11000000),
  147.   B8_1BIT(01000000),
  148.   B8_1BIT(01000000),
  149.   // Frame 3
  150.   B8_1BIT(00000000),
  151.   B8_1BIT(00000000),
  152.   B8_1BIT(00100000),
  153.   B8_1BIT(11100000),
  154.   // Frame 4
  155.   B8_1BIT(00000000),
  156.   B8_1BIT(10000000),
  157.   B8_1BIT(10000000),
  158.   B8_1BIT(11000000)
  159. };
  160. const uint8_t TetrisOData[] =
  161. {
  162.   // Frame 1
  163.   B8_3BIT(00000000),
  164.   B8_3BIT(00000000),
  165.   B8_3BIT(44000000),
  166.   B8_3BIT(44000000),
  167.   // Frame 2
  168.   B8_3BIT(00000000),
  169.   B8_3BIT(00000000),
  170.   B8_3BIT(44000000),
  171.   B8_3BIT(44000000),
  172.   // Frame 3
  173.   B8_3BIT(00000000),
  174.   B8_3BIT(00000000),
  175.   B8_3BIT(44000000),
  176.   B8_3BIT(44000000),
  177.   // Frame 4
  178.   B8_3BIT(00000000),
  179.   B8_3BIT(00000000),
  180.   B8_3BIT(44000000),
  181.   B8_3BIT(44000000)
  182. };
  183. const uint8_t TetrisOMask[] =
  184. {
  185.   // Frame 1
  186.   B8_1BIT(00000000),
  187.   B8_1BIT(00000000),
  188.   B8_1BIT(11000000),
  189.   B8_1BIT(11000000),
  190.   // Frame 2
  191.   B8_1BIT(00000000),
  192.   B8_1BIT(00000000),
  193.   B8_1BIT(11000000),
  194.   B8_1BIT(11000000),
  195.   // Frame 3
  196.   B8_1BIT(00000000),
  197.   B8_1BIT(00000000),
  198.   B8_1BIT(11000000),
  199.   B8_1BIT(11000000),
  200.   // Frame 4
  201.   B8_1BIT(00000000),
  202.   B8_1BIT(00000000),
  203.   B8_1BIT(11000000),
  204.   B8_1BIT(11000000)
  205. };
  206. const uint8_t TetrisSData[] =
  207. {
  208.   // Frame 1
  209.   B8_3BIT(00000000),
  210.   B8_3BIT(00000000),
  211.   B8_3BIT(05500000),
  212.   B8_3BIT(55000000),
  213.   // Frame 2
  214.   B8_3BIT(00000000),
  215.   B8_3BIT(50000000),
  216.   B8_3BIT(55000000),
  217.   B8_3BIT(05000000),
  218.   // Frame 3
  219.   B8_3BIT(00000000),
  220.   B8_3BIT(00000000),
  221.   B8_3BIT(05500000),
  222.   B8_3BIT(55000000),
  223.   // Frame 4
  224.   B8_3BIT(00000000),
  225.   B8_3BIT(50000000),
  226.   B8_3BIT(55000000),
  227.   B8_3BIT(05000000)
  228. };
  229. const uint8_t TetrisSMask[] =
  230. {
  231.   // Frame 1
  232.   B8_1BIT(00000000),
  233.   B8_1BIT(00000000),
  234.   B8_1BIT(01100000),
  235.   B8_1BIT(11000000),
  236.   // Frame 2
  237.   B8_1BIT(00000000),
  238.   B8_1BIT(10000000),
  239.   B8_1BIT(11000000),
  240.   B8_1BIT(01000000),
  241.   // Frame 3
  242.   B8_1BIT(00000000),
  243.   B8_1BIT(00000000),
  244.   B8_1BIT(01100000),
  245.   B8_1BIT(11000000),
  246.   // Frame 4
  247.   B8_1BIT(00000000),
  248.   B8_1BIT(10000000),
  249.   B8_1BIT(11000000),
  250.   B8_1BIT(01000000)
  251. };
  252. const uint8_t TetrisTData[] =
  253. {
  254.   // Frame 1
  255.   B8_3BIT(00000000),
  256.   B8_3BIT(00000000),
  257.   B8_3BIT(66600000),
  258.   B8_3BIT(06000000),
  259.   // Frame 2
  260.   B8_3BIT(00000000),
  261.   B8_3BIT(06000000),
  262.   B8_3BIT(66000000),
  263.   B8_3BIT(06000000),
  264.   // Frame 3
  265.   B8_3BIT(00000000),
  266.   B8_3BIT(00000000),
  267.   B8_3BIT(06000000),
  268.   B8_3BIT(66600000),
  269.   // Frame 4
  270.   B8_3BIT(00000000),
  271.   B8_3BIT(60000000),
  272.   B8_3BIT(66000000),
  273.   B8_3BIT(60000000)
  274. };
  275. const uint8_t TetrisTMask[] =
  276. {
  277.   // Frame 1
  278.   B8_1BIT(00000000),
  279.   B8_1BIT(00000000),
  280.   B8_1BIT(11100000),
  281.   B8_1BIT(01000000),
  282.   // Frame 2
  283.   B8_1BIT(00000000),
  284.   B8_1BIT(01000000),
  285.   B8_1BIT(11000000),
  286.   B8_1BIT(01000000),
  287.   // Frame 3
  288.   B8_1BIT(00000000),
  289.   B8_1BIT(00000000),
  290.   B8_1BIT(01000000),
  291.   B8_1BIT(11100000),
  292.   // Frame 4
  293.   B8_1BIT(00000000),
  294.   B8_1BIT(10000000),
  295.   B8_1BIT(11000000),
  296.   B8_1BIT(10000000)
  297. };
  298. const uint8_t TetrisZData[] =
  299. {
  300.   // Frame 1
  301.   B8_3BIT(00000000),
  302.   B8_3BIT(00000000),
  303.   B8_3BIT(77000000),
  304.   B8_3BIT(07700000),
  305.   // Frame 2
  306.   B8_3BIT(00000000),
  307.   B8_3BIT(07000000),
  308.   B8_3BIT(77000000),
  309.   B8_3BIT(70000000),
  310.   // Frame 3
  311.   B8_3BIT(00000000),
  312.   B8_3BIT(00000000),
  313.   B8_3BIT(77000000),
  314.   B8_3BIT(07700000),
  315.   // Frame 4
  316.   B8_3BIT(00000000),
  317.   B8_3BIT(07000000),
  318.   B8_3BIT(77000000),
  319.   B8_3BIT(70000000)
  320. };
  321. const uint8_t TetrisZMask[] =
  322. {
  323.   // Frame 1
  324.   B8_1BIT(00000000),
  325.   B8_1BIT(00000000),
  326.   B8_1BIT(11000000),
  327.   B8_1BIT(01100000),
  328.   // Frame 2
  329.   B8_1BIT(00000000),
  330.   B8_1BIT(01000000),
  331.   B8_1BIT(11000000),
  332.   B8_1BIT(10000000),
  333.   // Frame 3
  334.   B8_1BIT(00000000),
  335.   B8_1BIT(00000000),
  336.   B8_1BIT(11000000),
  337.   B8_1BIT(01100000),
  338.   // Frame 4
  339.   B8_1BIT(00000000),
  340.   B8_1BIT(01000000),
  341.   B8_1BIT(11000000),
  342.   B8_1BIT(10000000)
  343. };

  344. #define TETRIS_SPR_WIDTH  4
  345. #define TETRIS_SPR_HEIGHT 4
  346. const uint8_t *TetrisSprData[] = { TetrisIData, TetrisJData, TetrisLData, TetrisOData, TetrisSData, TetrisTData, TetrisZData };
  347. const uint8_t *TetrisSprMask[] = { TetrisIMask, TetrisJMask, TetrisLMask, TetrisOMask, TetrisSMask, TetrisTMask, TetrisZMask};
  348. const struct CRGB TetrisColours[] = { CRGB(0, 255, 255), CRGB(0, 0, 255), CRGB(255, 165, 0), CRGB(255, 255, 0), CRGB(50, 205, 50), CRGB(255, 0, 255), CRGB(255, 0, 0) };

  349. uint8_t PlayfieldData[MATRIX_HEIGHT * ((MATRIX_WIDTH + 7) / 8) * _3BIT];
  350. uint8_t PlayfieldMask[MATRIX_HEIGHT * ((MATRIX_WIDTH + 7) / 8) * _1BIT];
  351. uint8_t CompletedLinesData[TETRIS_SPR_HEIGHT * ((MATRIX_WIDTH + 7) / 8) * _1BIT];
  352. const struct CRGB CompletedLinesColour[] = { CRGB(255, 255, 255) };
  353. cSprite Playfield, CompletedLines, CurrentBlock;
  354. cLEDSprites Sprites(&leds);

  355. unsigned char AttractMsg[144], GameOverMsg[88];
  356. char BlankMsg[32];
  357. cLEDText TetrisMsg;

  358. uint8_t DropDelay;
  359. boolean AttractMode, NextBlock;
  360. int16_t TotalLines;
  361. unsigned int HighScore = 0, LastScore;

  362. uint16_t PlasmaTime, PlasmaShift;
  363. uint32_t LoopDelayMS, LastLoop;

  364. void setup()
  365. {
  366.   Serial.begin(115200);
  367.   SerialBT.begin("ESP32Tetris");
  368.   
  369.   FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size());
  370.   FastLED.setBrightness(200);
  371.   FastLED.clear(true);
  372.   FastLED.show();

  373.   memset(PlayfieldData, 0, sizeof(PlayfieldData));
  374.   memset(PlayfieldMask, 0, sizeof(PlayfieldMask));
  375.   Playfield.Setup(leds.Width(), leds.Height(), PlayfieldData, 1, _3BIT, TetrisColours, PlayfieldMask);
  376.   Playfield.SetPositionFrameMotionOptions(0, 0, 0, 0, 0, 0, 0, 0, 0);
  377.   Sprites.AddSprite(&Playfield);

  378.   memset(CompletedLinesData, 0, sizeof(CompletedLinesData));
  379.   CompletedLines.Setup(leds.Width(), TETRIS_SPR_HEIGHT, CompletedLinesData, 1, _1BIT, CompletedLinesColour, CompletedLinesData);
  380.   CompletedLines.SetPositionFrameMotionOptions(0, 0, 0, 0, 0, 0, 0, 0, 0);

  381.   TetrisMsg.SetFont(MatriseFontData);
  382.   sprintf((char *)BlankMsg, "%.*s", _min(((leds.Height() + TetrisMsg.FontHeight()) / (TetrisMsg.FontHeight() + 1)), (int)sizeof(BlankMsg) - 1), "                              ");
  383.   sprintf((char *)AttractMsg, "%sTETRIS%sSCORE %u%sHIGH %u%sANY BUTTON TO START%s", BlankMsg, BlankMsg, LastScore, BlankMsg, (int)HighScore, BlankMsg, BlankMsg);
  384.   TetrisMsg.Init(&leds, TetrisMsg.FontWidth() + 1, leds.Height(), (leds.Width() - TetrisMsg.FontWidth()) / 2, 0);
  385.   TetrisMsg.SetBackgroundMode(BACKGND_LEAVE);
  386.   TetrisMsg.SetScrollDirection(SCROLL_UP);
  387.   TetrisMsg.SetTextDirection(CHAR_UP);
  388.   TetrisMsg.SetFrameRate(1);
  389.   TetrisMsg.SetOptionsChangeMode(INSTANT_OPTIONS_MODE);
  390.   TetrisMsg.SetText(AttractMsg, strlen((const char *)AttractMsg));
  391.   AttractMode = true;
  392.   LoopDelayMS = TARGET_FRAME_TIME;
  393.   LastLoop = millis() - LoopDelayMS;
  394.   PlasmaShift = (random8(0, 5) * 32) + 64;
  395.   PlasmaTime = 0;
  396. }

  397. void loop()
  398. {
  399.   if (abs(millis() - LastLoop) >= LoopDelayMS)
  400.   {
  401.     LastLoop = millis();
  402.     FastLED.clear();

  403.     // Fill background with dim plasma
  404.     #define PLASMA_X_FACTOR  24
  405.     #define PLASMA_Y_FACTOR  24
  406.     for (int16_t x=0; x<MATRIX_WIDTH; x++)
  407.     {
  408.       for (int16_t y=0; y<MATRIX_HEIGHT; y++)
  409.       {
  410.         int16_t r = sin16(PlasmaTime) / 256;
  411.         int16_t h = sin16(x * r * PLASMA_X_FACTOR + PlasmaTime) + cos16(y * (-r) * PLASMA_Y_FACTOR + PlasmaTime) + sin16(y * x * (cos16(-PlasmaTime) / 256) / 2);
  412.         leds(x, y) = CHSV((uint8_t)((h / 256) + 128), 255, 64);
  413.       }
  414.     }
  415.     uint16_t OldPlasmaTime = PlasmaTime;
  416.     PlasmaTime += PlasmaShift;
  417.     if (OldPlasmaTime > PlasmaTime)
  418.       PlasmaShift = (random8(0, 5) * 32) + 64;

  419.     if (AttractMode)
  420.     {
  421.       if (currentInput != NONE)
  422.       {
  423.         AttractMode = false;
  424.         memset(PlayfieldData, 0, sizeof(PlayfieldData));
  425.         memset(PlayfieldMask, 0, sizeof(PlayfieldMask));
  426.         Sprites.RemoveSprite(&CurrentBlock);
  427.         LastScore = 0;
  428.         TotalLines = 0;
  429.         DropDelay = INITIAL_DROP_FRAMES;
  430.         CurrentBlock.SetXChange(-1);
  431.         NextBlock = true;
  432.         currentInput = NONE;
  433.       }
  434.     }
  435.     else
  436.     {
  437.       if (Sprites.IsSprite(&CompletedLines))  // We have highlighted complete lines, delay for visual effect
  438.       {
  439.         if (CompletedLines.GetXCounter() > 0)
  440.           CompletedLines.SetXCounter(CompletedLines.GetXCounter() - 1);
  441.         else
  442.         {
  443.           Sprites.RemoveSprite(&CompletedLines);
  444.           // Remove completed lines from playfield sprite
  445.           uint8_t *Data = PlayfieldData;
  446.           uint8_t *Mask = PlayfieldMask;
  447.           uint16_t Mbpl = (MATRIX_WIDTH + 7) / 8;
  448.           uint16_t Dbpl = Mbpl * _3BIT;
  449.           int16_t k;
  450.           for (int16_t i=(MATRIX_HEIGHT-1)*Dbpl,j=(MATRIX_HEIGHT-1)*Mbpl; i>=0; i-=Dbpl,j-=Mbpl)
  451.           {
  452.             for (k=0; k<MATRIX_WIDTH; k+=8)
  453.             {
  454.               if ((uint8_t)(0xff00 >> _min(MATRIX_WIDTH - k, 8)) != Mask[j + (k / 8)])
  455.                 break;
  456.             }
  457.             if (k >= MATRIX_WIDTH)
  458.             {
  459.               memmove(&Data[Dbpl], &Data[0], i);
  460.               memset(&Data[0], 0, Dbpl);
  461.               memmove(&Mask[Mbpl], &Mask[0], j);
  462.               memset(&Mask[0], 0, Mbpl);
  463.               i+=Dbpl;
  464.               j+=Mbpl;
  465.             }
  466.           }
  467.         }
  468.       }
  469.       else
  470.       {
  471.         if (CurrentBlock.GetXChange() >= 0) // We have a current block
  472.         {
  473.           // Check for user input
  474.           if ( currentInput == ROTATE )
  475.           {
  476.             currentInput = NONE;
  477.             if ((CurrentBlock.GetCurrentFrame() % 2) == 1)
  478.             {
  479.               if (CurrentBlock.GetXChange() == 0)
  480.                 CurrentBlock.m_X = _min(CurrentBlock.m_X, MATRIX_WIDTH - TETRIS_SPR_WIDTH);
  481.               else if ((CurrentBlock.GetXChange() != 3) && (CurrentBlock.GetFlags() & SPRITE_EDGE_X_MAX))
  482.                 --CurrentBlock.m_X;
  483.             }
  484.             CurrentBlock.IncreaseFrame();
  485.             Sprites.DetectCollisions(&CurrentBlock);
  486.             if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
  487.               CurrentBlock.DecreaseFrame();
  488.           }
  489.          
  490.           if ( currentInput == LEFT && (! (CurrentBlock.GetFlags() & SPRITE_EDGE_X_MIN)) )
  491.           {
  492.             currentInput = NONE;
  493.             CurrentBlock.m_X--;
  494.             Sprites.DetectCollisions(&CurrentBlock);
  495.             if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
  496.               CurrentBlock.m_X++;
  497.           }
  498.          
  499.           else if ( currentInput == RIGHT && (! (CurrentBlock.GetFlags() & SPRITE_EDGE_X_MAX)) )
  500.           {
  501.             currentInput = NONE;
  502.             CurrentBlock.m_X++;
  503.             Sprites.DetectCollisions(&CurrentBlock);
  504.             if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
  505.               CurrentBlock.m_X--;
  506.           }
  507.          
  508.           if ( currentInput == DOWN )
  509.           {
  510.             currentInput = NONE;
  511.             CurrentBlock.SetYCounter(1);
  512.           }
  513.             
  514.           // Do block checks for bottom or collision
  515.           if (CurrentBlock.GetYCounter() <= 1)
  516.           {
  517.             if (CurrentBlock.GetFlags() & SPRITE_EDGE_Y_MIN)
  518.               NextBlock = true;
  519.             else
  520.             {
  521.               --CurrentBlock.m_Y;
  522.               Sprites.DetectCollisions(&CurrentBlock);
  523.               ++CurrentBlock.m_Y;
  524.               if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
  525.               {
  526.                 // Block has collided check for game over
  527.                 int16_t MaxY = MATRIX_HEIGHT - 2;
  528.                 if ((CurrentBlock.GetCurrentFrame() % 2) == 1)
  529.                 {
  530.                   if (CurrentBlock.GetXChange() == 0)
  531.                     MaxY -= 2;
  532.                   else if (CurrentBlock.GetXChange() != 3)
  533.                     MaxY -= 1;
  534.                 }
  535.                 else if (CurrentBlock.GetXChange() == 0)
  536.                     ++MaxY;
  537.                 if (CurrentBlock.m_Y < MaxY)
  538.                   NextBlock = true;
  539.                 else
  540.                 {
  541.                   // Game over
  542.                   CurrentBlock.SetYCounter(2);  // Stop last block moving down!
  543.                   AttractMode = true;
  544.                   if (LastScore > HighScore)
  545.                   {
  546.                     HighScore = LastScore;
  547.                     sprintf((char *)GameOverMsg, "%sGAME OVER%sNEW HIGH SCORE %u%s", BlankMsg, BlankMsg, LastScore, BlankMsg);
  548.                   }
  549.                   else
  550.                     sprintf((char *)GameOverMsg, "%sGAME OVER%sSCORE %u%s", BlankMsg, BlankMsg, LastScore, BlankMsg);
  551.                   sprintf((char *)AttractMsg, "%sTETRIS%sSCORE %u%sHIGH %u%sANY BUTTON TO START%s", BlankMsg, BlankMsg, LastScore, BlankMsg, HighScore, BlankMsg, BlankMsg);
  552.                   TetrisMsg.SetText(GameOverMsg, strlen((char *)GameOverMsg));
  553.                   TetrisMsg.SetBackgroundMode(BACKGND_DIMMING, 0x40);
  554.                 }
  555.               }
  556.             }
  557.           }
  558.         }
  559.         if (NextBlock)  // Start new block
  560.         {
  561.           if (CurrentBlock.GetXChange() >= 0) // We have a current block so add to playfield before creating new block
  562.           {
  563.             Playfield.Combine(CurrentBlock.m_X, CurrentBlock.m_Y, &CurrentBlock);
  564.             Sprites.RemoveSprite(&CurrentBlock);
  565.             // Make completed lines highlight sprite & score
  566.             memset(CompletedLinesData, 0, sizeof(CompletedLinesData));
  567.             CompletedLines.m_Y = -1;
  568.             uint8_t *Mask = PlayfieldMask;
  569.             uint16_t Mbpl = (MATRIX_WIDTH + 7) / 8;
  570.             int16_t j, numlines = 0;
  571.             for (int16_t i=(MATRIX_HEIGHT-1)*Mbpl, y=0; i>=0; i-=Mbpl,++y)
  572.             {
  573.               for (j=0; j<MATRIX_WIDTH; j+=8)
  574.               {
  575.                 if ((uint8_t)(0xff00 >> _min(MATRIX_WIDTH - j, 8)) != Mask[i + (j / 8)])
  576.                   break;
  577.               }
  578.               if (j >= MATRIX_WIDTH)
  579.               {
  580.                 if (CompletedLines.m_Y == -1)
  581.                   CompletedLines.m_Y = y;
  582.                 memset(&CompletedLinesData[((TETRIS_SPR_HEIGHT - 1) - (y - CompletedLines.m_Y)) * Mbpl], 0xff, Mbpl);
  583.                 numlines++;
  584.               }
  585.             }
  586.             if (numlines > 0)
  587.             {
  588.               CompletedLines.SetXCounter(15);  // Set delay for highlight display to 15 loops
  589.               Sprites.AddSprite(&CompletedLines);
  590.             }
  591.             LastScore += 1;
  592.             if (numlines == 1)
  593.               LastScore += 4;
  594.             else if (numlines == 2)
  595.               LastScore += 12;
  596.             else if (numlines == 3)
  597.               LastScore += 20;
  598.             else if (numlines == 4)
  599.               LastScore += 40;
  600.             TotalLines += numlines;
  601.             DropDelay = _max(1, INITIAL_DROP_FRAMES - (TotalLines / 5));
  602.           }
  603.           // Start new block
  604.           uint8_t j = random8(sizeof(TetrisSprData) / sizeof(TetrisSprData[0]));
  605.           CurrentBlock.Setup(TETRIS_SPR_WIDTH, TETRIS_SPR_WIDTH, TetrisSprData[j], 4, _3BIT, TetrisColours, TetrisSprMask[j]);
  606.           CurrentBlock.SetPositionFrameMotionOptions((MATRIX_WIDTH/2)-1, MATRIX_HEIGHT, 0, 0, 0, 0, -1, DropDelay, SPRITE_DETECT_COLLISION | SPRITE_DETECT_EDGE);
  607.           CurrentBlock.SetXChange(j);
  608.           Sprites.AddSprite(&CurrentBlock);
  609.           NextBlock = false;
  610.         }
  611.         Sprites.UpdateSprites();
  612.       }
  613.     }
  614.     Sprites.RenderSprites();
  615.     if (AttractMode)
  616.     {
  617.       if (TetrisMsg.UpdateText() == -1)
  618.       {
  619.         TetrisMsg.SetText(AttractMsg, strlen((char *)AttractMsg));
  620.         TetrisMsg.SetBackgroundMode(BACKGND_LEAVE);
  621.         Sprites.RemoveSprite(&CurrentBlock);
  622.         memset(PlayfieldData, 0, sizeof(PlayfieldData));
  623.         memset(PlayfieldMask, 0, sizeof(PlayfieldMask));
  624.       }
  625.     }
  626.     FastLED.show();
  627.   }
  628.   if(SerialBT.available()){
  629.     char keyPress = (char)SerialBT.read();
  630.     switch(keyPress) {
  631.       case 'w':
  632.         currentInput = ROTATE;
  633.         break;
  634.       case 'a':
  635.         currentInput = LEFT;
  636.         break;
  637.       case 's':
  638.         currentInput = DOWN;
  639.         break;
  640.       case 'd':
  641.         currentInput = RIGHT;
  642.         break;
  643.     }
  644.     Serial.println(currentInput);
  645.   }
  646. }
 楼主| keer_zu 发表于 2025-5-21 14:35 | 显示全部楼层
只有背景的显示效果:
  1. // TETRIS
  2. #include <FastLED.h>
  3. #include <LEDMatrix.h>
  4. #include <LEDText.h>
  5. #include <FontMatrise.h>

  6. #define LED_PIN        15
  7. #define COLOR_ORDER    GRB
  8. #define CHIPSET        WS2812B
  9. #define MATRIX_WIDTH   30
  10. #define MATRIX_HEIGHT  15
  11. #define MATRIX_TYPE    HORIZONTAL_MATRIX

  12. // NOTE the '-' sign before the width, this is due to my leds matrix origin being on the right hand side
  13. cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;


  14. #define TARGET_FRAME_TIME    15  // Desired update rate, though if too many leds it will just run as fast as it can!

  15. uint16_t PlasmaTime, PlasmaShift;

  16. void setup()
  17. {
  18.   FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size());
  19.   FastLED.setBrightness(200);
  20.   FastLED.clear(true);
  21.   FastLED.show();

  22. PlasmaShift = (random8(0, 5) * 32) + 64;
  23.   PlasmaTime = 0;
  24. }

  25. void loop()
  26. {
  27.     FastLED.clear();

  28.     // Fill background with dim plasma
  29.     #define PLASMA_X_FACTOR  24
  30.     #define PLASMA_Y_FACTOR  24
  31.     for (int16_t x=0; x<MATRIX_WIDTH; x++)
  32.     {
  33.       for (int16_t y=0; y<MATRIX_HEIGHT; y++)
  34.       {
  35.         int16_t r = sin16(PlasmaTime) / 256;
  36.         int16_t h = sin16(x * r * PLASMA_X_FACTOR + PlasmaTime) + cos16(y * (-r) * PLASMA_Y_FACTOR + PlasmaTime) + sin16(y * x * (cos16(-PlasmaTime) / 256) / 2);
  37.         leds(x, y) = CHSV((uint8_t)((h / 256) + 128), 255, 64);
  38.       }
  39.     }

  40.     uint16_t OldPlasmaTime = PlasmaTime;
  41.     PlasmaTime += PlasmaShift;
  42.     if (OldPlasmaTime > PlasmaTime)
  43.       PlasmaShift = (random8(0, 5) * 32) + 64;

  44.     FastLED.show();
  45.     delay(10);
  46.   
  47. }
 楼主| keer_zu 发表于 2025-5-21 21:19 | 显示全部楼层
  1. // TETRIS
  2. #include <FastLED.h>
  3. #include <LEDMatrix.h>


  4. #define LED_PIN        15
  5. #define COLOR_ORDER    GRB
  6. #define CHIPSET        WS2812B
  7. #define MATRIX_WIDTH   30
  8. #define MATRIX_HEIGHT  15
  9. #define MATRIX_TYPE    HORIZONTAL_MATRIX

  10. // NOTE the '-' sign before the width, this is due to my leds matrix origin being on the right hand side
  11. cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;


  12. #define TARGET_FRAME_TIME    15  // Desired update rate, though if too many leds it will just run as fast as it can!

  13. uint16_t PlasmaTime, PlasmaShift;

  14. void setup()
  15. {
  16.   FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size());
  17.   FastLED.setBrightness(200);
  18.   FastLED.clear(true);
  19.   FastLED.show();

  20. PlasmaShift = (random8(0, 5) * 32) + 64;
  21.   PlasmaTime = 0;
  22. }

  23. void loop()
  24. {
  25.     // Fill background with dim plasma
  26.     #define PLASMA_X_FACTOR  24
  27.     #define PLASMA_Y_FACTOR  24
  28.     for (int16_t x=0; x<MATRIX_WIDTH; x++)
  29.     {
  30.       for (int16_t y=0; y<MATRIX_HEIGHT; y++)
  31.       {
  32.         int16_t r = sin16(PlasmaTime) / 256;
  33.         int16_t h = sin16(x * r * PLASMA_X_FACTOR + PlasmaTime) + cos16(y * (-r) * PLASMA_Y_FACTOR + PlasmaTime) + sin16(y * x * (cos16(-PlasmaTime) / 256) / 2);
  34.         leds(x, y) = CHSV((uint8_t)((h / 256) + 128), 255, 64);
  35.       }
  36.     }

  37.     uint16_t OldPlasmaTime = PlasmaTime;
  38.     PlasmaTime += PlasmaShift;
  39.     if (OldPlasmaTime > PlasmaTime)
  40.       PlasmaShift = (random8(0, 5) * 32) + 64;

  41.     FastLED.show();
  42.     delay(50);
  43.   
  44. }
 楼主| keer_zu 发表于 2025-5-22 08:19 | 显示全部楼层
限制颜色和平滑的效果(不理想)
  1. // TETRIS
  2. #include <FastLED.h>
  3. #include <LEDMatrix.h>

  4. #define LED_PIN        15
  5. #define COLOR_ORDER    GRB
  6. #define CHIPSET        WS2812B
  7. #define MATRIX_WIDTH   30
  8. #define MATRIX_HEIGHT  15
  9. #define MATRIX_TYPE    HORIZONTAL_MATRIX

  10. cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;

  11. #define TARGET_FRAME_TIME    15
  12. uint16_t PlasmaTime, PlasmaShift;

  13. void setup() {
  14.   FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size());
  15.   FastLED.setBrightness(200);
  16.   FastLED.clear(true);
  17.   PlasmaShift = (random8(0, 5) * 16) + 32;  // 降低变化速度
  18.   PlasmaTime = 0;
  19. }

  20. void loop() {
  21.   static uint8_t lastHue = 128;  // 用于色相平滑过渡
  22.   FastLED.clear();

  23.   // 更平滑的波形参数
  24.   #define PLASMA_X_FACTOR  16  // 降低X/Y方向波形频率
  25.   #define PLASMA_Y_FACTOR  16
  26.   #define HUE_START  96       // 青色
  27.   #define HUE_END    220       // 紫色
  28.   
  29.   for (int16_t x=0; x<MATRIX_WIDTH; x++) {
  30.     for (int16_t y=0; y<MATRIX_HEIGHT; y++) {
  31.       // 使用更平滑的波形组合
  32.       int16_t r = sin16(PlasmaTime * 0.7) / 512;  // 降低振幅变化速度
  33.       int16_t h = sin16(x * PLASMA_X_FACTOR + PlasmaTime * 0.5)
  34.                 + cos16(y * PLASMA_Y_FACTOR + PlasmaTime * 0.3)
  35.                 + sin16((x + y) * 64 + PlasmaTime * 0.4);  // 简化第三项波形

  36.       // 非线性映射 + 低通滤波平滑色相
  37.       uint8_t targetHue = map(h, -32768, 32767, HUE_START, HUE_END);
  38.       uint8_t hue = (targetHue * 0.3) + (lastHue * 0.7);  // 指数平滑
  39.       lastHue = hue;

  40.       leds(x, y) = CHSV(hue, 200, 100);
  41.     }
  42.   }

  43.   // 更缓慢的时间推进
  44.   PlasmaTime += PlasmaShift;
  45.   if (PlasmaTime % 512 == 0)  // 定期重置避免溢出
  46.     PlasmaShift = random8(0, 5) * 16 + 32;
  47.    
  48.   FastLED.show();
  49.   delay(20);
  50. }
 楼主| keer_zu 发表于 2025-5-22 10:50 | 显示全部楼层
随机变化的效果:

  1. // 风场参数
  2. const uint8_t scale = 25;       // 缩小缩放因子扩大波纹范围
  3. const uint8_t speed = 2;        // 降低运动速度
  4. const int8_t windDirection = 1;
  5. const uint8_t blurAmount = 48;  // 新增模糊系数
  6. uint16_t z = 0;
  7. // 优化的噪声生成函数
  8. void generateNoise(uint8_t *noiseData, uint16_t zOffset) {
  9.   for(uint8_t y=0; y<MATRIX_HEIGHT; y++) {
  10.     for(uint8_t x=0; x<MATRIX_WIDTH; x++) {
  11.       uint8_t xOffset = windDirection * beatsin8(
  12.         3,                    // 降低波浪频率
  13.         0, 15,               // 减小振幅范围
  14.         0,
  15.         (x * 2 + y * 3)      // 优化相位关系
  16.       );
  17.       
  18.       noiseData[XY(x,y)] = inoise8(
  19.         (x + xOffset) * scale,
  20.         y * scale * 1.2,     // Y轴增加缩放差异
  21.         zOffset
  22.       );
  23.     }
  24.   }
  25. }


  26. void wind_vision()
  27. {
  28.   static uint32_t lastUpdate = 0;
  29.   static uint8_t blendVal = 0;
  30.   
  31.   if(millis() - lastUpdate > 30) {
  32.     lastUpdate = millis();
  33.    
  34.     // 双缓冲噪声生成
  35.     uint8_t noiseData1[NUM_LEDS];
  36.     uint8_t noiseData2[NUM_LEDS];
  37.    
  38.     // 生成两帧噪声数据
  39.     generateNoise(noiseData1, z);
  40.     generateNoise(noiseData2, z + 50); // 50个时间单位偏移
  41.    
  42.     // 混合两帧数据
  43.     for(int i=0; i<NUM_LEDS; i++) {
  44.       uint8_t finalNoise = blend8(noiseData1[i], noiseData2[i], blendVal);
  45.       
  46.       // 扩展颜色映射范围
  47.       uint8_t hue = map(finalNoise, 40, 210, 180, 255); // 颜色范围180-255
  48.       uint8_t val = map(finalNoise, 60, 190, 50, 220);  // 保持亮度动态
  49.       
  50.       leds[i] = CHSV(hue, 245, val); // 略微降低饱和度
  51.     }
  52.    
  53.     // 应用二维模糊
  54.     blur2d(leds, MATRIX_WIDTH, MATRIX_HEIGHT, blurAmount);
  55.    
  56.     z += speed;
  57.     blendVal += 3; // 控制混合速度
  58.     FastLED.show();
  59.   }
  60. }


 楼主| keer_zu 发表于 2025-5-23 22:29 | 显示全部楼层

  1. #include <FastLED.h>

  2. // ========== 硬件配置 ==========
  3. #define LED_PIN       15
  4. #define LED_TYPE      WS2812B
  5. #define COLOR_ORDER   GRB
  6. #define MATRIX_WIDTH  30
  7. #define MATRIX_HEIGHT 15
  8. #define NUM_LEDS      (MATRIX_WIDTH * MATRIX_HEIGHT)
  9. CRGB leds[NUM_LEDS];

  10. // ========== 动画参数 ==========
  11. #define FRAME_RATE    30
  12. #define NOISE_SCALE   0.1f
  13. #define FLOW_SPEED    0.8f
  14. #define HUE_SPEED     0.02f
  15. #define BRIGHTNESS    80

  16. // ========== 全局变量 ==========
  17. float z;
  18. uint8_t hue_base;

  19. // ========== 完整的perm数组 ==========
  20. const uint8_t perm[256] = {
  21.   151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
  22.   140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
  23.   247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
  24.   57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
  25.   74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
  26.   60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
  27.   65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
  28.   200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
  29.   52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
  30.   207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
  31.   119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
  32.   129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
  33.   218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
  34.   81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
  35.   184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
  36.   222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
  37. };

  38. // ========== 修改后的噪声函数(重命名避免冲突)==========
  39. uint8_t custom_noise(uint16_t x, uint16_t y, uint16_t z) {
  40.   uint8_t a  = perm[(x>>8)&0xFF] + (y>>8);
  41.   uint8_t b  = perm[(y>>8)&0xFF] + (z>>8);
  42.   uint8_t aa = perm[a] + (z>>8);
  43.   uint8_t ba = perm[b] + (x>>8);
  44.   
  45.   uint8_t u = x & 0xFF;
  46.   uint8_t v = y & 0xFF;
  47.   
  48.   return lerp8by8(lerp8by8(perm[aa], perm[ba], u),
  49.                 lerp8by8(perm[aa+1], perm[ba+1], u), v);
  50. }

  51. // ========== 坐标映射函数 ==========
  52. uint16_t XY(uint8_t x, uint8_t y) {
  53.   if(y % 2 == 0) {
  54.     return y * MATRIX_WIDTH + x;
  55.   } else {
  56.     return (y + 1) * MATRIX_WIDTH - x - 1;
  57.   }
  58. }

  59. // ========== 主渲染函数(参数类型修正)==========
  60. void renderFrame() {
  61.   static float xOffset = 0;
  62.   static float yOffset = 0;
  63.   
  64.   xOffset += FLOW_SPEED * 0.7;
  65.   yOffset += FLOW_SPEED * 0.5;
  66.   hue_base += HUE_SPEED * 255;
  67.   z += 0.05;
  68.   
  69.   for(uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
  70.     for(uint8_t x = 0; x < MATRIX_WIDTH; x++) {
  71.       // 转换为整数参数
  72.       uint16_t nx = (uint16_t)(x * NOISE_SCALE * 256 + xOffset * 256);
  73.       uint16_t ny = (uint16_t)(y * NOISE_SCALE * 256 + yOffset * 256);
  74.       uint16_t nz = (uint16_t)(z * 256);
  75.       
  76.       uint8_t noise = (
  77.           custom_noise(nx, ny, nz) * 0.6 +
  78.           custom_noise(nx*2, ny*2, nz) * 0.4
  79.       );
  80.       
  81.       CRGB color = CHSV(noise + hue_base, 255, noise);
  82.       leds[XY(x,y)] = color;
  83.     }
  84.   }
  85. }

  86. void setup() {
  87.   FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  88.   FastLED.setBrightness(BRIGHTNESS);
  89.   FastLED.clear();
  90.   randomSeed(analogRead(0));
  91.   z = random(65536);
  92. }

  93. void loop() {
  94.   static uint32_t lastFrame = 0;
  95.   uint32_t frameInterval = 1000 / FRAME_RATE;
  96.   
  97.   if(millis() - lastFrame >= frameInterval) {
  98.     renderFrame();
  99.     FastLED.show();
  100.     lastFrame = millis();
  101.   }
  102.   yield();
  103. }
 楼主| keer_zu 发表于 2025-5-23 22:35 | 显示全部楼层

颜色受到限制的版本:
  1. #include <FastLED.h>

  2. // ========== 硬件配置 ==========
  3. #define LED_PIN      15
  4. #define LED_TYPE      WS2812B
  5. #define COLOR_ORDER   GRB
  6. #define MATRIX_WIDTH  30
  7. #define MATRIX_HEIGHT 15
  8. #define NUM_LEDS      (MATRIX_WIDTH * MATRIX_HEIGHT)
  9. CRGB leds[NUM_LEDS];

  10. // ========== 动画参数 ==========
  11. #define FRAME_RATE    30
  12. #define NOISE_SCALE   0.05f    // 更细腻的噪声图案
  13. #define FLOW_SPEED    0.3f     // 慢速流动
  14. #define HUE_SPEED     0.005f   // 缓慢色调变化
  15. #define BRIGHTNESS    80       // 中等亮度

  16. // ========== 全局变量 ==========
  17. float z;
  18. uint8_t hue_base;

  19. // ========== perm数组(保持不变)==========
  20. const uint8_t perm[256] = {
  21.   151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,
  22.   8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,
  23.   35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,
  24.   134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,
  25.   55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,
  26.   18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,
  27.   250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,
  28.   189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,
  29.   172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,
  30.   228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,
  31.   49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,
  32.   236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
  33. };

  34. // ========== 自定义噪声函数 ==========
  35. uint8_t custom_noise(uint16_t x, uint16_t y, uint16_t z) {
  36.   uint8_t a  = perm[(x>>8)&0xFF] + (y>>8);
  37.   uint8_t b  = perm[(y>>8)&0xFF] + (z>>8);
  38.   uint8_t aa = perm[a] + (z>>8);
  39.   uint8_t ba = perm[b] + (x>>8);
  40.   
  41.   uint8_t u = x & 0xFF;
  42.   uint8_t v = y & 0xFF;
  43.   
  44.   return lerp8by8(lerp8by8(perm[aa], perm[ba], u),
  45.                 lerp8by8(perm[aa+1], perm[ba+1], u), v);
  46. }

  47. // ========== 蛇形映射函数 ==========
  48. uint16_t XY(uint8_t x, uint8_t y) {
  49.   if(y % 2 == 0) {
  50.     return y * MATRIX_WIDTH + x;
  51.   } else {
  52.     return (y + 1) * MATRIX_WIDTH - x - 1;
  53.   }
  54. }

  55. // ========== 主渲染函数 ==========
  56. void renderFrame() {
  57.   static float xOffset = 0;
  58.   static float yOffset = 0;
  59.   
  60.   // 缓慢更新位置参数
  61.   xOffset += FLOW_SPEED * 0.7;
  62.   yOffset += FLOW_SPEED * 0.5;
  63.   hue_base += HUE_SPEED * 255;
  64.   z += 0.02;
  65.   
  66.   for(uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
  67.     for(uint8_t x = 0; x < MATRIX_WIDTH; x++) {
  68.       // 生成噪声参数
  69.       uint16_t nx = (uint16_t)(x * NOISE_SCALE * 256 + xOffset * 256);
  70.       uint16_t ny = (uint16_t)(y * NOISE_SCALE * 256 + yOffset * 256);
  71.       uint16_t nz = (uint16_t)(z * 256);
  72.       
  73.       // 混合噪声层
  74.       uint8_t noise = (
  75.           custom_noise(nx, ny, nz) * 0.6 +
  76.           custom_noise(nx*2, ny*2, nz) * 0.4
  77.       );
  78.       
  79.       // 颜色处理(限制在100-220 Hue范围)
  80.       uint8_t rawHue = noise + hue_base;
  81.       uint8_t scaledHue = scale8(rawHue, 120) + 100; // 120 = 60*2
  82.       CRGB color = CHSV(scaledHue, 200, noise);      // 适当降低饱和度
  83.       
  84.       leds[XY(x,y)] = color;
  85.     }
  86.   }
  87. }

  88. // ========== 初始化 ==========
  89. void setup() {
  90.   FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  91.   FastLED.setBrightness(BRIGHTNESS);
  92.   FastLED.clear();
  93.   randomSeed(analogRead(0));
  94.   z = random(65536);  // 随机初始Z值
  95. }

  96. // ========== 主循环 ==========
  97. void loop() {
  98.   static uint32_t lastFrame = 0;
  99.   uint32_t frameInterval = 1000 / FRAME_RATE;
  100.   
  101.   if(millis() - lastFrame >= frameInterval) {
  102.     renderFrame();
  103.     FastLED.show();
  104.     lastFrame = millis();
  105.   }
  106.   yield();
  107. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1477

主题

12909

帖子

55

粉丝
快速回复 在线客服 返回列表 返回顶部