Maker.io main logo

PixelDust Digital Sand Demos for Arcada

44

2024-10-09 | By Adafruit Industries

License: See Original Project LCD / TFT Adafruit Feather Grove STEMMA

Courtesy of Adafruit

Guide by Lady Ada

Overview

PyGamer and PyBadge have built in accelerometers - which you can ‎use in your games or demos to make nifty motion-activated effects. ‎In this mini guide we'll show you some examples ‎of PaintYourDragon's PixelDust library but for Arcada boards.

 

Supported Hardware

You'll need a board with Adafruit Arcada support + an accelerometer ‎such as...‎

Text editor powered by tinymce.‎

Start by following your board's guide on installing Arduino IDE, and ‎support for the board you have. Then install the Adafruit Arcada ‎libraries (there's a lot of em!)‎

Also install the Adafruit PixelDust library

sensors_ezgif-1-4b7d80e51b58

Compilation Settings

As you get to a few thousand particles, you'll want to speed up your ‎board as much as possible. Compile with ultra-speed settings such ‎as 200MHz overclock, -Ofast optimizations, and Cache enabled.‎

settings_1

Runtime Settings

There's not a lot of things you can adjust but here's a few common ‎ones:‎

#define CHUNKY_SAND‎

If this is at the top of the code, it will make each particle a 2x2 pixel ‎rather than a single pixel. this makes it look a little better, but you ‎can't fit as many particles on the screen.‎

#define N_FLAKES 2000

How many particles to simulate. More look cooler but too many and ‎it slows down! 1000-2000 seems to be a good number, especially ‎with CHUNKY_SAND turned on.‎

On this line in the loop:‎

pixeldust->iterate(xx 3000.0, yy 3000.0, zz * 3000.0);‎

The multiplier affects the 'gravity' of the pixels. Larger numbers will ‎drag the pixels down faster, smaller numbers will make the pixels ‎float a little more.‎

Snow Demo

Start with the pixeldust_demos->pixeldust_snow example, it’s the ‎simplest demo - each pixel is the same white color.‎

demo_2

Upload and enjoy!‎

upload_3

Sand Demo

This demo builds on the snow version to add speckled yellow colors ‎to each particle, to create a sand-effect!‎

sand_4

You can add color to each pixel by creating a new array of 16-bit ‎colors as we do in this demo with the creation of uint16_t ‎‎*flake_colors; and then later flake_colors = (uint16_t )malloc(N_FLAKES 2).‎

Then you can assign the colors, we'll use an HSV picker to find a hue ‎we think is sandy...‎

colors_5

And randomly assign brightness/saturations so we get a range of ‎sandy colors!‎

‎Download File

Copy Code
  // randomize colors
  for (int i=0; i< N_FLAKES; i++) {
    flake_colors[i] = 
      __builtin_bswap16(arcada.ColorHSV565(40, // Hue (sandy)
                                           random(50, 100),  // saturation
                                           random(50, 100))); // brightness
  }

Note we use __builtin_bswap16 on each color word. That's because we ‎later use DMA to write out all the pixels and we need to have the ‎high/low bytes of color swapped in order for it to run as fast as ‎possible (it’s a weird effect of TFT DMA on Arduino)‎.

Later on, when we draw the pixels, we'll look up the corresponding ‎color before we draw the color to our framebuffer:‎

‎Download File

Copy Code
  for(int i=0; i<N_FLAKES; i++) {
    pixeldust->getPosition(i, &x, &y);
    //Serial.printf("(%d, %d) -> %d\n", x, y, x * width + y);
    uint16_t flakeColor = flake_colors[i];
#ifdef CHUNKY_SAND
    framebuffer[2*y * width + 2*x] = flakeColor;
    framebuffer[2*y * width + 2*x+1] = flakeColor;
    framebuffer[(2*y+1) * width + 2*x] = flakeColor;
    framebuffer[(2*y+1) * width + 2*x + 1] = flakeColor;
#else
    framebuffer[y * width + x] = flakeColor;
#endif
  }

Logo Demo

Finally, the most advanced of the demos adds a logo 'obstacle' both ‎as an image and a 'mask' that tells PixelDust where not to let pixels ‎go. This makes for lovely effects as particles slide around.‎

sensors_ezgif-1-247db949ce6f

For the logo, which is 8-bit grayscale and stored in the header, you ‎can use a tool like this that will take an image and convert it into a ‎header file.‎

Like the sand demo we will store a color for each particle. Except this ‎time instead of randomly placing them on the display, they are put ‎into boxes along the bottom of the screen:‎

Download File

Copy Code
  // Set up initial sand coordinates, in 8x8 blocks
  int n = 0;
  for(int i=0; i<N_COLORS; i++) {
    int xx = i * play_width / N_COLORS;
    int yy =  play_height - BOX_HEIGHT;
    for(int y=0; y<BOX_HEIGHT; y++) {
      for(int x=0; x<play_width / N_COLORS; x++) {
        //Serial.printf("#%d -> (%d, %d)\n", n,  xx + x, yy + y);
        pixeldust->setPosition(n++, xx + x, yy + y);
      }
    }
  }

Since the chunks of particle divide up into 8 colors, we don’t have to ‎store the color of each one, we know that the index of the particle, ‎divided by 8, gives the color index. Notes we have to bswap16 the color ‎here like we did before.‎

‎Download File

Copy Code
  colors[0] = arcada.color565(40 , 40, 40);   // Dark Gray
  colors[1] = arcada.color565(120, 79, 23);   // Brown
  colors[2] = arcada.color565(228,  3,  3);   // Red
  colors[3] = arcada.color565(255,140,  0);   // Orange
  colors[4] = arcada.color565(255,237,  0);   // Yellow
  colors[5] = arcada.color565(  0,128, 38);   // Green
  colors[6] = arcada.color565(  0, 77,255);   // Blue
  colors[7] = arcada.color565(117,  7,135); // Purple
  for (int i=0; i<N_COLORS; i++) {
    colors[i] = __builtin_bswap16(colors[i]);  // we swap the colors here to speed up DMA
  }

Then before we draw all the particles, we also have to draw the logo:‎

Download File

Copy Code
  int logo_origin_x = (width  - 2*LOGO_WIDTH ) / 2;
  int logo_origin_y = (height - 2*LOGO_HEIGHT ) / 2;
  // Draw the logo atop the background...
  for(int yl=0; yl<LOGO_HEIGHT; yl++) {
    for(int xl=0; xl<LOGO_WIDTH; xl++) {
      uint16_t c = 
         __builtin_bswap16(arcada.color565(logo_gray[yl][xl], logo_gray[yl][xl], logo_gray[yl][xl]));
      x = logo_origin_x + 2*xl;
      y = logo_origin_y + 2*yl; 
      
      framebuffer[y * width + x] = c;
      framebuffer[y * width + x+1] = c;
      framebuffer[(y+1) * width + x] = c;
      framebuffer[(y+1) * width + x+1] = c;
    }
  }

Text editor powered by tinymce.‎

Mfr Part # 4277
PYGAMER STARTER KIT
Adafruit Industries LLC
More Info
View More Details
Mfr Part # 4242
PYGAMER FOR MAKECODE ARCADE, CIR
Adafruit Industries LLC
More Info
View More Details
Mfr Part # 4200
ADAFRUIT PYBADGE FEATHER
Adafruit Industries LLC
More Info
View More Details
Mfr Part # 592
CABLE A PLUG TO MCR B PLUG 3'
Adafruit Industries LLC
More Info
View More Details
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.