M5STACK(その4)

みんながM5STACKにArduinoのスケッチを移植してるのが楽しそうで、自分もやってみたくなった。

でも自分じゃ簡単なのじゃないととても無理なので、画面に何か表示させるだけのスケッチを探す。

で、懐かしのFlying Toasterがあったので、これでやってみた。

元ネタは以下。

 https://learn.adafruit.com/animated-flying-toaster-oled-jewelry/

以前これ作ろうとして3Dプリンタでケースだけ作ってたことがあったので、せっかくだから勉強がてらM5STACKで完成させてやることにした。

 

元ネタだと振動スイッチでオンしたり、15秒経過でスリープしたりという機能が付いてるみたいだけど、そういうのはめんどくさいので一切抜きにしました。

(というかエラーが出たらサクサク該当箇所を削除してった感じ)

あくまでもハードは本体のM5STACKのみ。

M5STACKだけでもスイッチはあるし、バッテリーも考えなくていいのでとても楽。

あとは画面のサイズが違うので、該当する箇所の数字を変更。

使用する画像はそのまま、bitmaps.hを使用した。ただ、最初の文を変更。

 #include <Arduino.h>

を、

 #include <pgmspace.h>

にする。

 

そしてビットマップ表示のコマンドも、ほぼそのまま…と思いきや、これで引っかかった。

元ネタが

 display.drawBitmap(x, y, (const uint8_t *)pgm_read_word(&mask[f]), 32, 32, BLACK);
 display.drawBitmap(x, y, (const uint8_t *)pgm_read_word(&img[ f]), 32, 32, WHITE);

だったので、「display.drawBitmap」を「M5.Lcd.drawBitmap」にした。

しかしコンパイルしたら画面が白黒の点滅を繰り返すだけで、画像が出てこなくて悩みに悩んだ。

で、問題だったのは「pgm_read_word」と「&」の存在だけで、結局

 M5.Lcd.drawBitmap(x, y,  (const uint8_t*)mask[f], 32, 32, BLACK);
 M5.Lcd.drawBitmap(x, y,  (const uint8_t*)img[f], 32, 32, WHITE);

にしたら通った。悩んだけど、最終的にシンプルになったのは良いと思う。

 

無事にスケッチが転送されると、トーストとトースターが飛びます。

これであのBGMが鳴ったら完璧だけど、それはそれでめんどくさい。(何より曲忘れた)

しかしちょっと画面がチカチカしすぎかな。そこは調整が必要。

しかもあんまりランダムじゃなくて、なんか隅っこに行きがち。

 

ビットマップの「img」組と「mask」組の意味がよくわからなかったので、imgの方だけ表示させてます。それでもあんまり変わらないように見える。

黒いビットマップでマスクして動きを滑らかにしたかったのかも。でも自分がそれを活かしきれてない気がする。

 

以下に自分がカスタムしたスケッチを置いておくので、興味ある方はいじって使ってみてください。

(で、さらに良い感じにカスタムしてくれたら嬉しい)

bitmaps.hは最初の一行を変えるだけなので、そっちは載せません。

 

#include <M5Stack.h>
#include "bitmaps.h" // Toaster graphics data is in this header file

#define N_FLYERS   10 // Number of flying things

struct Flyer {       // Array of flying things
  int16_t x, y;      // Top-left position * 16 (for subpixel pos updates)
  int8_t  depth;     // Stacking order is also speed, 12-24 subpixels/frame
  uint8_t frame;     // Animation frame; Toasters cycle 0-3, Toast=255
} flyer[N_FLYERS];

uint32_t startTime;

void setup()
{
  M5.begin();

  randomSeed(analogRead(2));
  M5.Lcd.clearDisplay();

  for(uint8_t i=0; i<N_FLYERS; i++) {  // Randomize initial flyer states
    flyer[i].x     = (-32 + random(160)) * 16;
    flyer[i].y     = (-32 + random(96)) * 16;
    flyer[i].frame = random(3) ? random(4) : 255; // 66% toaster, else toast
    flyer[i].depth = 10 + random(16);             // Speed / stacking order
  }
  qsort(flyer, N_FLYERS, sizeof(struct Flyer), compare); // Sort depths
}
void loop()
{
  uint8_t i, f;
  int16_t x, y;
  boolean resort = false;     // By default, don't re-sort depths

  M5.Lcd.display();          // Update screen to show current positions
  M5.Lcd.clearDisplay();     // Start drawing next frame
  
  for(i=0; i<N_FLYERS; i++) { // For each flyer...

    // First draw each item...
    f = (flyer[i].frame == 255) ? 4 : (flyer[i].frame++ & 3); // Frame #
    x = flyer[i].x / 16;
    y = flyer[i].y / 16;
//M5.Lcd.drawBitmap(x, y,  (const uint8_t*)mask[f], 32, 32, BLACK);
  M5.Lcd.drawBitmap(x, y,  (const uint8_t*)img[f], 32, 32, WHITE);

    // Then update position, checking if item moved off screen...
    flyer[i].x -= flyer[i].depth * 2; // Update position based on depth,
    flyer[i].y += flyer[i].depth;     // for a sort of pseudo-parallax effect.
    if((flyer[i].y >= (240*16)) || (flyer[i].x <= (-32*16))) { // Off screen?
      if(random(7) < 5) {         // Pick random edge; 0-4 = top
        flyer[i].x = random(160) * 16;
        flyer[i].y = -32         * 16;
      } else {                    // 5-6 = right
        flyer[i].x = 320         * 16;
        flyer[i].y = random(240)  * 16;
      }
      flyer[i].frame = random(3) ? random(4) : 255; // 66% toaster, else toast
      flyer[i].depth = 10 + random(16);
      resort = true;
    } 
  }
}
// Flyer depth comparison function for qsort()
static int compare(const void *a, const void *b) {
  return ((struct Flyer *)a)->depth - ((struct Flyer *)b)->depth;

}

Sponsered Link
コメント