M5StickCのDisplay周り解析 その2

※現時点の情報ですので、最新情報はM5StickC非公式日本語リファレンスを確認してください。

概要

M5StackCのライブラリが更新されたので、描画周りの動きを再度説明したいと思います。基本的な動作は前回の記事と変わっていませんので、気をつける機能と追加機能を中心に紹介します。

文字色の補足

#include <M5StickC.h>
void setup() {
  // 共通初期化
  M5.begin();
  M5.Axp.ScreenBreath(8);   // 7-12
  M5.Lcd.setRotation(0);    // 0-3
  M5.Lcd.fillScreen(BLACK);
  // 背景色は透過色(塗りつぶさない)
  int y = 4;
  M5.Lcd.setTextSize(2);                  // 2倍サイズ
  M5.Lcd.setCursor(0, y);                 // カーソル移動
  M5.Lcd.setTextColor(BLUE);              // 青(背景色無し)
  M5.Lcd.println("BLUE");                 // テキスト描画
  M5.Lcd.setCursor(0, y);                 // カーソル移動
  M5.Lcd.setTextColor(RED);               // 赤(背景色無し)
  M5.Lcd.println("RED");                  // テキスト描画
  // 背景色はグレー(塗りつぶしあり)
  y += 16;
  M5.Lcd.setTextSize(2);                  // 2倍サイズ
  M5.Lcd.setCursor(0, y);                 // カーソル移動
  M5.Lcd.setTextColor(BLUE, LIGHTGREY);   // 青(背景色グレー)
  M5.Lcd.println("BLUE");                 // テキスト描画
  M5.Lcd.setCursor(0, y);                 // カーソル移動
  M5.Lcd.setTextColor(RED, LIGHTGREY);    // 赤(背景色グレー)
  M5.Lcd.println("RED");                  // テキスト描画
  // 背景色は透過色(塗りつぶしあり) スペースで塗りつぶし
  y += 16;
  M5.Lcd.setTextSize(2);                  // 2倍サイズ
  M5.Lcd.setCursor(0, y);                 // カーソル移動
  M5.Lcd.setTextColor(BLUE, LIGHTGREY);   // 青(背景色グレー)
  M5.Lcd.printf("%-5s\n", "BLUE");        // テキスト描画
  M5.Lcd.setCursor(0, y);                 // カーソル移動
  M5.Lcd.setTextColor(RED, LIGHTGREY);    // 赤(背景色グレー)
  M5.Lcd.printf("%-5s\n", "RED");         // テキスト描画
}
void loop() {
}

フォント描画色のデフォルトはM5.Lcd.setTextColor(WHITE, BLACK)になっていると思いますが、色指定をした場合に、背景色の指定をしない場合には塗りつぶしなしになるので注意しましょう。

1行目は透過色無しのため、最初に描画したBLUEの一部がREDを描画したあとでも残っています。

2行目は透過色にグレーを指定しましたが、BLUEの4文字に対して、REDが3文字のためEの文字が残っています。

3行目は透過色にグレーを指定して、printfで長さ5文字の左詰めに指定しています。文字列のあとに自分でスペースを入れて、描画幅を指定しても同じ効果があります。

  M5.Lcd.printf("BLUE ");        // テキスト描画
  M5.Lcd.printf("RED  ");        // テキスト描画

文字色指定は塗りつぶしの色も含めて、2色を指定したほうが楽だと思います。

TFT_eSpriteクラス

#include <M5StickC.h>
TFT_eSprite tftSprite = TFT_eSprite(&M5.Lcd);
void setup() {
  // 共通初期化
  M5.begin();
  M5.Axp.ScreenBreath(8);   // 7-12
  M5.Lcd.setRotation(0);    // 0-3
  M5.Lcd.fillScreen(BLACK);
  tftSprite.createSprite(M5.Lcd.width(), M5.Lcd.height());
  // 背景色は透過色(塗りつぶさない)
  int y = 4;
  tftSprite.setTextSize(2);                  // 2倍サイズ
  tftSprite.setCursor(0, y);                 // カーソル移動
  tftSprite.setTextColor(BLUE);              // 青(背景色無し)
  tftSprite.println("BLUE");                 // テキスト描画
  tftSprite.setCursor(0, y);                 // カーソル移動
  tftSprite.setTextColor(RED);               // 赤(背景色無し)
  tftSprite.println("RED");                  // テキスト描画
  // 背景色はグレー(塗りつぶしあり)
  y += 16;
  tftSprite.setTextSize(2);                  // 2倍サイズ
  tftSprite.setCursor(0, y);                 // カーソル移動
  tftSprite.setTextColor(BLUE, LIGHTGREY);   // 青(背景色グレー)
  tftSprite.println("BLUE");                 // テキスト描画
  tftSprite.setCursor(0, y);                 // カーソル移動
  tftSprite.setTextColor(RED, LIGHTGREY);    // 赤(背景色グレー)
  tftSprite.println("RED");                  // テキスト描画
  // 背景色は透過色(塗りつぶしあり) スペースで塗りつぶし
  y += 16;
  tftSprite.setTextSize(2);                  // 2倍サイズ
  tftSprite.setCursor(0, y);                 // カーソル移動
  tftSprite.setTextColor(BLUE, LIGHTGREY);   // 青(背景色グレー)
  tftSprite.printf("%-5s\n", "BLUE");        // テキスト描画
  tftSprite.setCursor(0, y);                 // カーソル移動
  tftSprite.setTextColor(RED, LIGHTGREY);    // 赤(背景色グレー)
  tftSprite.printf("%-5s\n", "RED");         // テキスト描画
  tftSprite.pushSprite(0, 0);                // 実際に描画する
}
void loop() {
}

先ほどと同じ処理をTFT_eSpriteクラスを使って見ました。TFT_eSpriteは直接画面に描画するのではなく、メモリ上に描画エリアを作り、そこに描画を行う処理になります。最終的にpushSprite()関数を呼び出すと、画面に転送して実際の描画がはじまります。

メモリ上に描画エリアを作るので、ダブルバッファなどと呼ばれることがあります。一度バッファに書き込んでから、一括して描画の転送を行うので高速描画が可能です。通常の描画の場合、ピクセル単位で画面に転送を行っていますが、ダブルバッファからであれば、指定した範囲を一括転送することが可能です。

メモリ上の描画エリアのことはキャンバスと呼ぶ場合が多いですが、TFT_eSpriteの場合にはスプライトと呼ぶと思います。

一般的にスプライトはキューティングゲームなどでは、自機や敵キャラクターなどに相当します。同じような敵が複数でる場合には、同じスプライトを描画することができますし、スプライト同士の当たり判定などを計算したりもできます。

TFT_eSpriteの場合には、本来のスプライトとして小さいのを複数個ではなく、ダブルバッファとして画面全体を1個だけ使うパターンが多いようです。

複数スプライトを使ってみる

#include <M5StickC.h>
TFT_eSprite tftSprite1 = TFT_eSprite(&M5.Lcd);
TFT_eSprite tftSprite2 = TFT_eSprite(&M5.Lcd);
void setup() {
  // 共通初期化
  M5.begin();
  M5.Axp.ScreenBreath(8);   // 7-12
  M5.Lcd.setRotation(0);    // 0-3
  M5.Lcd.fillScreen(LIGHTGREY);
  tftSprite1.createSprite(64, 20);
  tftSprite2.createSprite(64, 20);
  // BG背景色は黄色で、TEXT青のTEXTBGが赤
  tftSprite1.fillScreen(YELLOW);
  tftSprite1.setTextSize(2);                  // 2倍サイズ
  tftSprite1.setCursor(0, 0);                 // カーソル移動
  tftSprite1.setTextColor(BLUE, RED);         // 青(背景色赤)
  tftSprite1.println("BLUE");                 // テキスト描画
  // BG背景色は黄色で、TEXT青のTEXTBGが赤
  tftSprite2.fillScreen(YELLOW);
  tftSprite2.setTextSize(2);                  // 2倍サイズ
  tftSprite2.setCursor(0, 0);                 // カーソル移動
  tftSprite2.setTextColor(BLACK, WHITE);      // 黒(背景色白)
  tftSprite2.println("BLACK");                // テキスト描画
  int y = 4;
  tftSprite1.pushSprite(4, y);                // 実際に描画する
  y += 24;
  tftSprite1.pushSprite(4, y, YELLOW);        // 実際に描画する(YELLOWは描画しない)
  y += 24;
  tftSprite2.pushSprite(4, y);                // 実際に描画する
  y += 24;
}
void loop() {
}

複数の場合です。

2行目は透過色を指定しての描画ですので、黄色が描画されていません。キャラクターを描画する場合などはこの指定で描画が可能だと思います。

回転させる

#include <M5StickC.h>
TFT_eSprite tftSprite0 = TFT_eSprite(&M5.Lcd);
void setup() {
  // 共通初期化
  M5.begin();
  M5.Axp.ScreenBreath(8);   // 7-12
  M5.Lcd.setRotation(0);    // 0-3
  M5.Lcd.fillScreen(LIGHTGREY);
  M5.Lcd.setPivot(40, 80);
  tftSprite0.createSprite(48, 20);
  // BG背景色は黄色で、TEXT青のTEXTBGが赤
  tftSprite0.setPivot(0, 0);
  tftSprite0.fillScreen(YELLOW);
  tftSprite0.setTextSize(2);                  // 2倍サイズ
  tftSprite0.setCursor(0, 0);                 // カーソル移動
  tftSprite0.setTextColor(BLUE, RED);         // 青(背景色赤)
  tftSprite0.println("Rot");                  // テキスト描画
}
void loop() {
  for (int16_t angle = 0; angle < 360; angle+=10) {
    //M5.Lcd.fillScreen(LIGHTGREY);
    tftSprite0.pushRotated(angle);
    delay(50);
  }
}

スプライトのsetPivot()でスプライトの回転座標を決めて、M5.Lcd.setPivot()の座標に描画されます!

非常に謎な関数仕様ですが、文字を縦に表示したいときには便利そうですね。

日本語(マルチバイト文字)を描画したい

上記のフォントデータを、Arduino IDEのライブラリマネージャーに登録しました。ライブラリマネージャーよりefontを追加してもらうと、日本語描画が可能です。

TFT_eSpriteにはまだ対応していませんが、描画可能です。

もっと描画を早くしたい

標準の描画ロジックは非常に遅いです。上記のらびやんさんが開発中の「LovyanGFX」は非常に高速描画が可能なライブラリです。

使い方はある程度互換性がありますが微妙に違いますので、今後紹介していきたいと思います。

まとめ

ちょっとスプライトはクセがありますが、ライブラリのバージョンアップによりスプライトが使いやすくなりました。

続編

コメント