【micro:bit × Processing】魔法を使ってる風を装ってみる

#はじめに
最近Processingにはまり、この前の4連休はジェネラティブアート作って遊んでいました。
「ハァッ！」とか叫んで手を振るとブワッと円が描画されたら魔法的な雰囲気を醸し出せて楽しいのでは...？と思いmicro:bitの力を借りて作ってみました。
<img width="600" alt="スクリーンショット 2020-07-30 0.04.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533386/7c65d289-81c8-28d5-0de2-a6173980b58c.png">
▼動かしている動画はこちら
https://twitter.com/rntkym0618/status/1287712456442175488?s=20

#用意するもの
- micro:bit
- Micro USBケーブル
- ProcessingをダウンロードしたPC
- PCとMicro USBケーブルを接続するアダプター
- micro:bitを固定する手袋（薬局に売っている綿手袋を改造）

何気に手袋にmicro:bit入れるポケット縫うのが一番しんどかった。
え、裁縫ってこんなに難しかったっけ？？家庭科の授業でエプロン作れた小学生の私と同一人物？？と困惑してます。
<img width="400" alt="スクリーンショット 2019-11-27 22.07.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533386/ba70a8a0-551f-94a6-aa82-f75465b3aa85.png">

#micro:bitのブロック
[ブロック全体はこちら](https://makecode.microbit.org/98884-65717-38748-89975)

###ジェスチャーと対応する光の挙動
micro:bitで特定のジェスチャーを取得して、その情報をシリアル通信でProcessingに送ります。

|  ジェスチャー  |  光（円）の挙動  |
| ---- | ---- |
|  左に傾ける  |  小さな光が左に動く  |
|  右に傾ける  |  小さな光が右に動く  |
|  奥に傾ける  |  小さな光が上に動く  |
|  手前に傾ける  |  小さな光が下に動く  |
|  手を垂直に勢いよく前へ押す  |  画面いっぱいに光る  |
|  手を水平に勢いよく横に動かす  |  横一直線に光る  |

###傾きの取得
micro:bitでは「どの方向にどれだけ傾いたか」という数値を取ることができます。

- ロール：左右の傾きを取得 / 値の範囲は-180° ~ 180°
- ピッチ：上下の傾きを取得 / 値の範囲は-90° ~ 90°
<img width="400" alt="スクリーンショット 2020-07-29 22.47.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533386/76573dcd-3123-5dd9-a494-28e16260015c.png">

###勢いの取得
micro:bitでは「どの方向にどれだけはやく動いたか」という数値を取ることができます。
x, y, z, 3軸の絶対値の加速度を取ることができるようで、今回は絶対値を使いました。
<img width="400" alt="スクリーンショット 2020-07-29 23.06.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533386/6c743e5f-1090-0281-4de2-2d3ec1d13651.png">

micro:bitを動かして値を観察してみると、ぶんぶん動かした時に値が2000程度になったので「勢いよく動かした」と判断する境界を加速度2000に定めました。

#Processingのコード
[コード全体はこちら](https://github.com/rntkym/magic-glove/blob/master/magic_glove/magic_glove.pde)

###micro:bitとのシリアル通信
[こちらの記事](https://qiita.com/kikpond15/items/e9256ead4779f365a1a3)を参考にさせていただきました！
`Serial.list()`に接続できるポートのリストが格納されています。micro:bitは`usbmodem`の方で1番目に格納されてました。
`115200`はUSBシリアル通信の通信速度らしいです。（bps）
`bufferUntil(10)`によって改行を読み取ったら`serialEvent`を呼び出します。

```java:magic_glove.pde
import processing.serial.*;
Serial microbit;

void setup() {
  surface.setSize(1500, 900); 

  microbit = new Serial(this, Serial.list()[1], 115200);
  microbit.bufferUntil(10);
}
```

呼び出された`serialEvent`がこちら。ここで読み取った情報を整形していきます。
改行まで読んで一つの文字列に格納 → micro:bitではカンマ区切りで情報を送ってたのでカンマ区切りで配列に格納 → 1つ1つ変数に格納、といった流れです。

```java:magic_glove.pde
void serialEvent(Serial microbit) {
  String str = microbit.readStringUntil('\n');
  String[] info = str.split(",");
  if(info.length == 5){
    x = float(info[0]);
    y = float(info[1]);
    attribute = float(info[2]);
    magic1 = float(info[3]);
    magic2 = float(info[4]);
  }
}
```

###受け取った値をもとに描画する
ランダムって...面白！！...この一言に尽きる。

```java:magic_glove.pde
int order = 0;
float red, green, blue, opacity, x, y, size, attribute, magic1, magic2;

void draw() {
  int volume = 1;
  background(0);
  
  //ジェスチャーによって表示される円の数（volumeの値）を設定
  if(magic1 == 1 || magic2 == 1){
    volume = 200;
    order = 0;
  }
  
  for(int i = 0; i < volume; i ++){
    //不透明度の設定
    opacity = random(200);

    //micro:bitのボタンを押すことで変化するattributeの値によってRGB値を設定
    if(attribute == 1){
      red = random(50);
      green = random(100, 150);
      blue = random(150);
    }
    //分岐で同じようなコードが続くので省略
    
    //描画される円の位置とサイズをジェスチャーによって場合分け
    if (magic1 == 1){
      x = random(width);
      y = height / 2 + random(-50, 50);
      size = random(100);
    }
    else if(magic2 == 1){
      x = random(width);
      y = random(height);
      size = random(200);
    }
    else{
      x = x + random(-20, 20);
      y = y + random(-20, 20);
      size = random(50);
    }

    //設定した値をまとめて描画する用の配列に格納
    float[] args = {red, green, blue, opacity, x, y, size};
    array[order] = args;
    
    //まとめて描画する円は300個までとして、それ以降は上書きする
    order += 1;
    if(order == 300){
      order = 0;
    }
  }

  //円を描画。drawが呼ばれる度に円の大きさを小さくするように更新していく
  for(int i = 0; i < 300; i ++){
    fill(array[i][0], array[i][1], array[i][2], array[i][3]);
    noStroke();
    ellipse(array[i][4], array[i][5], array[i][6], array[i][6]);
    array[i][6] -= 1;
    if(array[i][6] < 0){
      array[i][6] = 0;
    }
  }
}
```

#最後に
手袋をもっとこう...格好良くしたい