ScratchX でレポーターブロック(Reporter blocks)を作る

[ScratchX で非同期のコマンドブロック(Asynchronous command)を作る](http://qiita.com/mironal/items/180c3af71942ad42fa3e) の続きです。

---

今回はレポーターブロックを作ります。

レポーターブロックとはこんな感じのやつです。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/06a9b3d8-655d-d37a-3da7-48adf1cbae14.png)

緑のブロックのように白い穴に入れた値を計算して新しい値を別のブロックに渡したり、青のブロックのように別のブロックに値を渡したりするブロックです。

## 事前準備

前回の [ScratchX の Extension をローカルで開発する環境を整える](http://qiita.com/mironal/items/99779c4d307fb004bee7) で作った環境をベースにして作業をしていきます。

環境が無い方は是非記事を参考にして整えてみてください。

# 同期レポーターブロックを作る

同期レポーターブロックはすぐに値を別のブロックに渡せる場合に使います。

先ほど貼り付けた画像のブロックは全て同期レポーターブロックです。

今回は三角形の面積を求めるレポーターブロックを作ってみたいと思います。

## 完成イメージ

完成イメージはこんな感じです。

`底辺 ◯ 高さ ◯ の三角系の面積` というブロックが今回作るものです。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/8bb3c107-5c95-b361-ff94-b2806bc4e044.png)

## Extension を作る

前回作った `log_extension.js` を編集します。

主に

1. triangle_area 関数を追加
2. descriptor のところを修正

をやっているだけです。 書くのが面倒だったらまるごとコピペしちゃってください。

```js:log_extension.js
(function(ext) {

  // コメントは補足の説明なので書かなくてもいいです

  // Extension が終了するときに呼ばれる
  // 今は特に何もしない
  ext._shutdown = function() {};

  // Extension の状態を返す
  // デバイスが繋がっていないときにはエラーを返したりする
  // ---
  // 返す値, 表示される色, 意味
  //      0,          red, error
  //      1,       yellow, not ready
  //      2,        green, ready
  // ---
  // 今回はデバイスなどは使用しないので常に準備完了
  // ということで 2 を返します。
  ext._getStatus = function() {
    return {status: 2, msg: 'Ready'};
  };

  ext.triangle_area = function(a, b) {
    return a * b / 2;
  };

  // wait 秒待ってから str を表示するブロック
  ext.wait_log = function(wait, str, callback) {
    setTimeout(function() {
      alert(str);
      callback();
    }, wait * 1000);
  };

  // この関数がブロック処理になります。
  ext.log = function(str) {
    // ログを出力するだけ
    alert(str);
  };

  // ブロックをどういう風に表示するかを書きます
  // ここの書き方は結構難しいので今は説明しません
  var descriptor = {
    blocks: [
      [' ', 'log %s', 'log', 'sample log'],
      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log'],
      ['r', '底辺 %n, 高さ %n の三角系の面積', 'triangle_area', 2, 3]
    ]
  };

  // Scratch に作ったブロックを登録します
  ScratchExtensions.register('Log Extension', descriptor, ext);
})({});
```

diff はこんな感じです。

```diff 
diff --git a/src/log_extension.js b/src/log_extension.js
index 349ac6e..0f48439 100644
--- a/src/log_extension.js
+++ b/src/log_extension.js
@@ -20,6 +20,10 @@
     return {status: 2, msg: 'Ready'};
   };
 
+  ext.triangle_area = function(a, b) {
+    return a * b / 2;
+  };
+
   // wait 秒待ってから str を表示するブロック
   ext.wait_log = function(wait, str, callback) {
     setTimeout(function() {
@@ -39,7 +43,8 @@
   var descriptor = {
     blocks: [
       [' ', 'log %s', 'log', 'sample log'],
-      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log']
+      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log'],
+      ['r', '底辺 %n, 高さ %n の三角系の面積', 'triangle_area', 2, 3]
     ]
   };
 
```

保存したら実際に ScratchX に読み込ませて使ってみます。

## ScratchX で使ってみる

まずはローカルサーバーを起動します。

前回と同じ手順です。

terminal で`package.json` のあるディレクトリに移動して `npm start` を実行します。

そしたら `http://scratchx.org/?url=http://localhost:8080/log_extension.js` をブラウザで開いて `I understand, continue` という緑色のボタンを押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/8f3906d4-3dd4-91db-a495-1373e3f2b3ba.png)

すると今作った `底辺 ② 高さ ③ の三角系の面積` というブロックが追加されていると思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/2cb29e76-c6d3-1512-b034-884831ace989.png)

ちょっと複雑ですが、こんな感じにブロックを組んで実行してみましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/884b1ef4-12b6-c4c1-3ac3-a2ec15aa70c4.png)

実行すると以下の様な感じで喋ります。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/f43ac3e6-0f07-6a16-e81b-59304500040e.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/e4a1a9e2-2c3d-c6dc-b266-7dfafdc64c41.png)

同期レポーターブロックに関しては以上です。

# 非同期レポーターブロックを作る

お次は非同期のレポーターブロックを作ります。

非同期レポーターブロックはすぐに値を別のブロックに渡せない場合に使います。

例えばインターネットで通信して値を取得するものだったり、値の取得に時間のかかるセンサーを使う場合などです。

今回はインターネット上で公開されている [OpenWeatherMap](http://openweathermap.org/) というサービスを使って東京の気温を取得するブロックを作ってみたいと思います。

今回作るこのブロックは値(気温)を取得するためにインターネットで通信する必要があるので、値の取得に少し時間がかかります(数ミリ秒程度)。

こういった時間がかかる処理を同期レポーターブロックで作ってしまうと他のブロックの動作に影響を与えてしまうため非同期で行います。具体的には処理が完了するまで他のブロックの動作を止めてしまいます。

## 完成イメージ

完成イメージはこんな感じです。 

`東京の気温` というブロックが今回作るブロックです。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/91a4add9-8a0f-58e8-2323-87cd55f5511d.png)

## Extension を作る

今回も `log_extension.js` を編集します。

主に

1. temp_of_tokyo 関数を追加
2. descriptor のところを修正

をやっているだけです。 書くのが面倒だったらまるごとコピペしちゃってください。

```js:log_extension.js
(function(ext) {

  // コメントは補足の説明なので書かなくてもいいです

  // Extension が終了するときに呼ばれる
  // 今は特に何もしない
  ext._shutdown = function() {};

  // Extension の状態を返す
  // デバイスが繋がっていないときにはエラーを返したりする
  // ---
  // 返す値, 表示される色, 意味
  //      0,          red, error
  //      1,       yellow, not ready
  //      2,        green, ready
  // ---
  // 今回はデバイスなどは使用しないので常に準備完了
  // ということで 2 を返します。
  ext._getStatus = function() {
    return {status: 2, msg: 'Ready'};
  };

  // 東京の気温を取得する
  ext.temp_of_tokyo = function(callback) {

    var param = {
      q: "tokyo",
      appid: "ddd98c6a715c25fd4a3b45e64c34bb10",
      units: "metric"
    };

    // 気象情報 API にアクセス
    $.get("http://api.openweathermap.org/data/2.5/weather", param, function(data) {
      callback(data.main.temp);
    });
  };

  ext.triangle_area = function(a, b) {
    return a * b / 2;
  };

  // wait 秒待ってから str を表示するブロック
  ext.wait_log = function(wait, str, callback) {
    setTimeout(function() {
      alert(str);
      callback();
    }, wait * 1000);
  };

  // この関数がブロック処理になります。
  ext.log = function(str) {
    // ログを出力するだけ
    alert(str);
  };

  // ブロックをどういう風に表示するかを書きます
  // ここの書き方は結構難しいので今は説明しません
  var descriptor = {
    blocks: [
      [' ', 'log %s', 'log', 'sample log'],
      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log'],
      ['r', '底辺 %n, 高さ %n の三角系の面積', 'triangle_area', 2, 3],
      ['R', '東京の気温', 'temp_of_tokyo']
    ]
  };

  // Scratch に作ったブロックを登録します
  ScratchExtensions.register('Log Extension', descriptor, ext);
})({});

```

diff はこんな感じです。

```diff
diff --git a/src/log_extension.js b/src/log_extension.js
index 0f48439..380878e 100644
--- a/src/log_extension.js
+++ b/src/log_extension.js
@@ -20,6 +20,21 @@
     return {status: 2, msg: 'Ready'};
   };
 
+  // 東京の気温を取得する
+  ext.temp_of_tokyo = function(callback) {
+
+    var param = {
+      q: "tokyo",
+      appid: "ddd98c6a715c25fd4a3b45e64c34bb10",
+      units: "metric"
+    };
+
+    // 気象情報 API にアクセス
+    $.get("http://api.openweathermap.org/data/2.5/weather", param, function(data) {
+      callback(data.main.temp);
+    });
+  };
+
   ext.triangle_area = function(a, b) {
     return a * b / 2;
   };
@@ -44,7 +59,8 @@
     blocks: [
       [' ', 'log %s', 'log', 'sample log'],
       ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log'],
-      ['r', '底辺 %n, 高さ %n の三角系の面積', 'triangle_area', 2, 3]
+      ['r', '底辺 %n, 高さ %n の三角系の面積', 'triangle_area', 2, 3],
+      ['R', '東京の気温', 'temp_of_tokyo']
     ]
   };
```



## ScratchX で使ってみる

ローカルサーバーを起動して `http://scratchx.org/?url=http://localhost:8080/log_extension.js` をブラウザで開いて `I understand, continue` という緑色のボタンを押します。

そしたら `東京の気温` というブロックがあると思います。 無かったらなにか間違えているのでプログラムを見なおしてください。

下の画像を参考にしてブロックを組んで実行すると吹き出しに現在の気温が表示されます。

下の画像では 5.95 度ですが、実行するときによって気温は変わるので表示も変わります。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/91a4add9-8a0f-58e8-2323-87cd55f5511d.png)

---

## まとめ

今回は同期レポーターブロックと非同期レポーターブロックを作りました。

同期レポーターブロックでは自分の好きな計算式を使って計算した結果を別のブロックに渡せるので、複雑な計算もブロック1つでできるようになるので便利だと思います。

非同期レポーターブロックはインターネット(Web API)を使って値を取得する場合などの時間がかかる処理の場合に使います。 ちょっと上級者向けの機能ですが使えるようになるとたくさんのことができるようになります。


残すはハットブロックのみですが、その前に今まで説明をしてこなかった `descriptor` の部分について説明したいと思います。

```js
  var descriptor = {
    blocks: [
      [' ', 'log %s', 'log', 'sample log'],
      ['w', 'wait %s secs and log %s', 'wait_log', 1, 'sample log'],
      ['r', '底辺 %n, 高さ %n の三角系の面積', 'triangle_area', 2, 3],
      ['R', '東京の気温', 'temp_of_tokyo']
    ]
  };
```

という部分です。