Step05 画像データを表示する


#1

今回はライブラリのdrawBitmap関数を使います。

変換は手軽なウェブページ上で行います。
Chromeブラウザ専用です。持ってない方はお手数ですがインストールをお願いします。

■手順

  1. 画像を右クリック → 「画像をコピー」を選択。
  2. fuopyさんのページを開いてください。
  3. Ctrl + v(ペースト)すると、ページ上に画像が表示されます。
  4. 画像をクリックすればテキストにコピーされます。

あとはIDE上で必要な部分にCtrl + v してください。

#include <Arduboy.h>

const static unsigned char img[] PROGMEM =
{
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc,
0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc,
0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f,
0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f,
0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
};

Arduboy ab;

void setup()
{
    ab.beginNoLogo();
    ab.setFrameRate(30);
    ab.clear();

    ab.drawBitmap(0, 0, img, 32, 32, 1);

    ab.display();
}

void loop()
{
    if(!(ab.nextFrame()))
    {
        return;
    }

    // EMPTY
}

変換するのが大量にある場合、img2ardを使ってください。
別途、自作してみるのもいいと思います。

もう1つ画像を用意してアニメーションさせてみましょう。

#include <Arduboy.h>

const static unsigned char img0[] PROGMEM =
{
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc,
0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc,
0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f,
0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f,
0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
};

const static unsigned char img1[] PROGMEM =
{
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc,
0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc,
0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00,
0xf0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f,
0x0f, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00,
0x0f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xf0, 0xe0,
0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f,
0x3f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f,
0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00,
};

Arduboy ab;
uint8_t frame = 0;

void setup()
{
    ab.beginNoLogo();
    ab.setFrameRate(30);
}

void loop()
{
    if(!(ab.nextFrame()))
    {
        return;
    }

    ab.clear();

    if(frame >= 15)
    {
        ab.drawBitmap(0, 0, img0, 32, 32, 1);
    }
    else
    {
        ab.drawBitmap(0, 0, img1, 32, 32, 1);
    }

    ab.display();

    if(++frame > 30)
    {
        frame = 0;
    }
}

ちなみにこれは、口が開いたり閉じたりする黄色のキャラクタではなく、
ホールケーキが増えたり減ったりアニメーションです(汗。

・・・さて、ちょっとゲームを作ったことがある方なら、drawBitmapの引数や、
描画関連全体に不満が出てくると思います。

・引数uint8_t w, hはコード側ではなくて、データ側に持たすべきでは?
・マスクビット用の関数がほしい。背景の上に書いたら潰れません?
・アニメーションしたいときはどうするの?
・ハード的にできなくてもスプライトはないの?

この辺りの答えは、今のところTeam a.r.gさんのコードにありそうです。
私としてはそのうちパクろうと考えています。


(hisadg) #2

img2ard はデータ先頭に width と height を出力するため、drawBitmapで使う際はご注意を。マスクデータも出力してくれるので、スプライトには便利そうです :slight_smile:


#3

補足ありがとうございます。

できればタイルモード(ドラクエ1のマップ表示)もほしいのですけど
ライブラリの更新がほとんどないですし、今の状況だと難しそうです。


(hisadg) #4

スプライトやタイルもやってるゲームは出てきてはいるんですよね。いい感じにノウハウが貯まって、ライブラリにフィードバックされていくといいなと思います :relaxed:


(koteitan) #5

class Sprites ですね。

あと、私は

 void drawBitmap(
   int16_t xdst, /* display position */
   int16_t ydst, /* display position */
   const uint8_t *bitmap, 
   int16_t xsrc, /* position on bitmap */
   int16_t ysrc, /* position on bitmap */
   uint8_t w, 
   uint8_t h, 
   uint8_t color
);

が欲しくなりました。
高さが全部 8 ピクセル固定なら必要ないのですが高さ 8 ピクセル未満のキャラクタを書くときに1枚のbitmapに詰め込むことでプログラムメモリを食わなくなります。(描画時間はたぶん最大倍になりますが)


#6

8x8dot日本語フォントとかOLED直接描画とかいろいろ試した感じでは、データで数十バイト減らしても描画するプログラムが使うメモリ(Flash)の増加で帳消しになるようです。
※表示しようとしている画像データよりプログラムの方が大きい場合があるので、できるだけ少ない回数で描画する必要がある

作るゲームの処理方法にもよりますが、メモリ(Flash)不足になるようなら「ビット演算などでブロック単位になるようにデータを生成→drawBitmapで描画」などの泥臭い実装が必要かもしれません。近いうちに具体的な実証コードが示せると思います。