池袋晶葉ちゃんSSRが可愛いので衣装の一部をobnizで再現した

6月10日の池袋晶葉誕生日祭が終わったと思ったらその翌日にデレステでSSRが実装されました。
なんてこった。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ソーシャルゲームのスクリーンショットです <a href="https://t.co/AZrMu88Ijp">pic.twitter.com/AZrMu88Ijp</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1006127705408954368?ref_src=twsrc%5Etfw">2018年6月11日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**引きました。**

お財布的には大丈夫な範囲です。
**ええ、大丈夫です。**

ところでこの衣装すごくて、晶葉ちゃんの背負っているランドセル改め**ニャンドセル**のお顔が動くんですよ。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr"><a href="https://t.co/143GlqE4yz">pic.twitter.com/143GlqE4yz</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1007819130269921281?ref_src=twsrc%5Etfw">2018年6月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こんな感じ。
可愛い。

で、前回の記事で使ったobnizさん。

[池袋晶葉ちゃん誕生日に向けてobnizで動くウサちゃんロボを作った](https://qiita.com/youdie_/items/b7aa7c9b37b416e5e234)

obniz自体にもディスプレイがついているので、ニャンドセルのお顔が再現できるのでは？と思いやってみました。

## canvasでアニメを作ろう

obnizのディスプレイはHTML5のcanvasを利用して描画ができます。
canvasなら好き放題できるし、アニメーションも作りやすそうなのでこれでいってみましょう。

というわけで今回はひたすらにcanvasでアニメを作るやつです。
obnizがどうこうというより初心者がやってみたcanvasアニメーションって感じになりそう。

流れとしてはこんな感じ。

1. canvasでニャンドセルの顔を作る
1. 差分を作る
1. obniz.repeatでループする

やっていきます。

### 1. canvasでニャンドセルの顔を作る

まずobnizでのcanvasの扱い方です。

obnizのクラスからcanvasのcontextが取れます。

```javascript:JavaScript
const ctx = obniz.util.createCanvasContext(obniz.display.width, obniz.display.height);
```

obnizのディスプレイは128*64なので、その中でいい塩梅になるようにひったすらにcanvasでパスを引きまくります。
canvasでのお絵描きの方法は世の中にいっぱい情報があると思うので割愛しますね。

**ちなみにまあまあ大変。**

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ニャンドセルを再現すべくcanvasにパスを引きまくってたらこんな時間かよ <a href="https://t.co/174zDR6h3L">pic.twitter.com/174zDR6h3L</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1006566642350866432?ref_src=twsrc%5Etfw">2018年6月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

単純にJavaScriptでcanvas使ってるだけなので、obnizに適用する前にローカルでブラウザデバッグできるのもいいですね。


### 2. 差分を作る

canvasでアニメを作るときの基本は、

* 描画する
* 全部消す
* 差分を描画する

の繰り返しです。

というわけでアニメにするための差分を作ります。

今回動かすのは目と口ですね。

なので目と口を描画するメソッドをそれぞれ作って、引数で描画パターンを変えられるようにします。

```javascript:目を描画メソッド

    var drawEye = (ctx,ptn) => {

      switch(ptn){
        case 0: //開いてるパターン

          //左目
          ctx.beginPath();
          ctx.arc(37, 37, 7, (Math.PI/180)*0, (Math.PI/180)*360, false);
          ctx.fill();

          //右目
          ctx.beginPath();
          ctx.arc(91, 37, 7, (Math.PI/180)*0, (Math.PI/180)*360, false);
          ctx.fill();

          break;
        case 1: //閉じてるパターン

          //左目
          ctx.beginPath();
          ctx.moveTo(44,42);
          ctx.lineTo(30,42);
          ctx.stroke();

          //右目
          ctx.beginPath();
          ctx.moveTo(84,42);
          ctx.lineTo(98,42);
          ctx.stroke();

          break;
        case 2: //半開きパターン

          //左目
          ctx.beginPath();
          ctx.arc(37, 37, 7, (Math.PI/180)*315, (Math.PI/180)*225, false);
          ctx.fill();

          //右目
          ctx.beginPath();
          ctx.arc(91, 37, 7, (Math.PI/180)*315, (Math.PI/180)*225, false);
          ctx.fill();

          break;
      }

      return ctx;

    }

```

こんな感じでcontextとパターンを引数にして描画を変えてます。

円を描くためのラジアン計算をベタで書いてるのは許してください。
最後にcontextを返却してるのは特に意味はありません。なんとなくです。

これで描画素材がそろいました。

### 3. obniz.repeatでループする

ループアニメを作ります。

JavaScriptでループといえばsetIntervalとかがありますが、obnizさんはそれ独自のループ用メソッド`obniz.repeat`を持っています。

使い方はsetIntervalと変わりませんが、こちらはobnizとの通信が切れたところでループを止めてくれるという親切なラッパーメソッドになっています。
せっかくなのでこっちを使いましょう。

はい、最終的にこんなソースになりました（canvasの描画処理は割愛）

```javascript:JavaScript
var obniz = new Obniz("XXXXXXXX");
obniz.onconnect = async () => {

  const ctx = obniz.util.createCanvasContext(obniz.display.width, obniz.display.height);

  //ループで使う描画メソッド
  var draw = (ctx, ePtn, mPtn) => {

    //canvasをクリア
    ctx.clearRect(0,0,128,64);

    // 線の塗りを設定する（単一色）
    ctx.strokeStyle = "#fff";
    ctx.fillStyle = "#fff";

    // 線の太さを設定する
    ctx.lineWidth = 1.0;

    ctx.beginPath();

    //耳とか日がどかぶちとか動かないものを描画（割愛）

    //目を描画メソッド
    var drawEye = (ctx,ptn) => {

      switch(ptn){
        case 0: 
          //開いてるパターン
          break;
        case 1:
          //閉じてるパターン
          break;
        case 2:
          //半開きパターン
          break;
      }

      return ctx;

    }

    //目を引数のパターンで描画
    ctx = drawEye(ctx,ePtn);

    //口を描画メソッド
    var drawMouth = (ctx,ptn) => {

      //開くパターンの時はちょっと上にずらす
      var y = 0;
      if(ptn == 1){y = -2;}

      ctx.lineWidth = 1.5;
      ctx.beginPath();
      ctx.arc(58, 50 + y, 7, (Math.PI/180)*30, (Math.PI/180)*150, false);
      ctx.stroke();
      ctx.beginPath();
      ctx.arc(70, 50 + y, 7, (Math.PI/180)*150, (Math.PI/180)*30, true);
      ctx.stroke();

      //開いたときの口の下の線
      if(ptn == 1){
        ctx.beginPath();
        ctx.arc(64, 50, 9, (Math.PI/180)*30, (Math.PI/180)*150, false);
        ctx.stroke();
      }

      return ctx;

    }

    //口を引数のパターンで描画
    ctx = drawMouth(ctx, mPtn);

  }

  var eyePtn = 0;
  var mouthPtn = 0;
  var counter = 0;

  //ループスタート
  obniz.repeat(()=>{

    switch (counter) {
      case 0:
        eyePtn = 0;
        mouthPtn = 0;
        counter++
        break;
      case 1:
        eyePtn = 1;
        mouthPtn = 0;
        counter++
        break;

      case 2:
        eyePtn = 2;
        mouthPtn = 0;
        counter++
        break;

      case 3:
        eyePtn = 0;
        mouthPtn = 0;
        counter++
        break;

      case 4:
        eyePtn = 0;
        mouthPtn = 1;
        counter++
        break;

      case 5:
        eyePtn = 0;
        mouthPtn = 0;
        counter = 0;
        break;
    }

    //描画処理
    draw(ctx, eyePtn, mouthPtn);

    //描画したcontextをobnizに渡す
    obniz.display.draw(ctx);

  },300);
  
}

```

ちょっぴり補足解説。
今回のアニメは

1. 初期顔
2. 目を閉じる
3. 目が半開きになる
4. 目が開く（初期顔）
5. 口が開く
6. 口を閉じる（初期顔）

の6コマあります。
目：3パターン、口：2パターンを順番に描画していけばいいわけですね。
そこで`obniz.repeat`メソッドの中でカウンターを使って状記6パターンの描画を切り替えています。

最後の300は切り替えのミリ秒数でsetIntervalとまんま同じ使い勝手です。

## ワハハ完成したぞ

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">池袋晶葉のSSR実装祝いに新衣装のニャンドセルの顔をobniz上で再現してみました <a href="https://t.co/xbehMVBtqG">pic.twitter.com/xbehMVBtqG</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1006917600192880642?ref_src=twsrc%5Etfw">2018年6月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**かーわいーー**

はい、そんな感じでできました。
最初のcontext生成とループ処理以外はほとんどcanvasの描画処理なので、あんまりonbiz特有っぽさはないですね。

逆に言うとcanvasでできることは全部obniz上にも描画できるということですけれど。
obnizから他のディスプレイを操作したりできるともっと色々夢が広がりそうですね。