Blocklyに触ってみよう！

# 昨年に続き、AdventCalendarやりますよ！
ALH Advent Calendar1日目です！（おや？投稿日が…）

個人的なお話をすると、2020年は職務領域を広げて、採用にも携わるように。
とはいえ、やっぱりエンジニアでいたい気持ちはあるので、
ちょっとしたことでもいいから、**ものづくりで組織に貢献していきたいな**って思います。

そんなこんなで、今年は**Blocklyについて**書いてみようと思います！

# Blocklyって何？
**Googleがオープンソースとして提供しているビジュアルプログラミングのライブラリ**です！

- ブロックタイプ
- 無料で使える
- 100%クライアントサイドのライブラリ

言葉だけでは分かりづらいと思いますが、
[公式のサンプルゲーム](https://blockly.games/?lang=ja)があったり、
[Hour of code](https://hourofcode.com/jp)というWebサービスにも用いられています！
ぜひ一度覗いてみて、「こんな風にできるんだ！」とご理解いただければと思います。

# どんなことをしたの？
**ちょっとしたビジュアルプログラミングを用いたゲームを作成**しました！
詳細は、以下の記事をご覧ください！
[CANTABILE - Zoomで内定者インターンを実施しました！](https://cantabile.alhinc.jp/detail/?post=3541)

# どうやって使うの？
私もすべてを使いこなせているわけではありませんが、
振り返りもかねて、簡単に使い方を記載いたします！

[公式ドキュメント](https://developers.google.com/blockly)がかなり豊富なので、
困ったら公式に頼りましょう！
※私も実際は公式ドキュメントを読み漁りました。

## 1. ワークスペースを用意する
ワークスペース、つまり作業場所ですね。
選択したブロックをドラック&ドロップで移動させたり、
ブロック同士をつなげたりする場所のことです。

参考：[Fixed-sized Workspace](https://developers.google.com/blockly/guides/configure/web/fixed-size)

``` html
<html lang="ja">
<head>
  <meta charset="utf-8"/>
  <script src="https://cdn.jsdelivr.net/npm/blockly@1.0.0/blockly_compressed.min.js"></script>    <!-- ライブラリを読み込む -->
  <script src="https://cdn.jsdelivr.net/npm/blockly@1.0.0/blocks_compressed.min.js"></script>     <!-- ライブラリを読み込む -->
  <script src="https://cdn.jsdelivr.net/npm/blockly@1.0.0/javascript_compressed.min.js"></script> <!-- ライブラリを読み込む -->
  <script src="https://cdn.jsdelivr.net/npm/blockly@1.0.0/msg/js/ja.min.js"></script>             <!-- 日本語化 -->
  <title>Blockly Sample</title>
</head>
<body>
  <div id="blocklyDiv" style="height: 480px; width: 600px;"></div>                                <!-- ワークスペースを用意 -->
  <xml id="toolbox" style="display: none">                                                        <!-- ブロックサンプルを用意 -->
    <block type="controls_if"></block>
    <block type="controls_repeat_ext"></block>
    <block type="logic_compare"></block>
    <block type="math_number"></block>
    <block type="math_arithmetic"></block>
    <block type="text"></block>
    <block type="text_print"></block>
  </xml>
  <script>
    var workspace = Blockly.inject('blocklyDiv',                                                  // ライブラリに読み込ませる
      {toolbox: document.getElementById('toolbox')});
  </script>
</body>
</html>
```

何も考えず上記をコピペし、HTMLとして開いてみてください。
※CDNを利用しているため、ネットワーク環境をご用意ください。

下記のような表示になるはずです。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188440/5d98c4f3-5b0f-4953-0f78-560b0bed61da.png)

**これだけで使えるようになっているんです！すごくないですか！？**
ブロックをドラッグ&ドロップで移動したり、ブロック同士をくっつける挙動も既に用意されています。
試してみてください！
※私はこの段階で感動しました（笑）

## 2. オリジナルのブロックを用意する
何かしらオリジナルのサービスを作ろうと思ったら、オリジナルのブロックが必要になりますよね。
Google先生はそこもきっちり用意してくれています（笑）

参考：[Blockly Developer Tools](https://blockly-demo.appspot.com/static/demos/blockfactory/index.html)

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188440/e3b1d817-59f3-a2ad-8ed8-f736f23df71a.png)

ぱっと見だと使い方が分からないので、簡単に説明いたします。

1. **①**の`Input`や`Field`タブから用意したいブロックに沿ったブロックを選び、ブロックに繋げていきます。  
   するとリアルタイムに**②の`Preview`**が更新されるので、用意したいブロックになっているか確認しましょう。  
   ※`name`属性でブロックを一意に判断するので、分かりやすい名前にしましょう。
2. **③**の`Block Definition`や`Generator stub`は、設定として取り込むための記述を示しています。  
   JSONやJavascriptなど、いくつかの言語が用意されていますので、適した言語で利用しましょう。  
   ※ここではJavascriptを使用します。
3. 用意したJavascriptをHTMLにコピペし、1.で設定した`name`を`block`タグの`type`で指定します。  
   すると、オリジナルブロックが表示されます。

あまりステップが無かったです（笑）
**それだけ簡単に、オリジナルブロックを用意して使うことができるということですね！**

兎に角弄ってみることが理解につながると思いますので、
色々触ってみてください！

## 3. ブロックのコードを実行する
さぁ、あとは組み立てたブロック達のコードを実行するだけです！

参考：[Generating and Running JavaScript](https://developers.google.com/blockly/guides/app-integration/running-javascript)

``` js
Blockly.JavaScript.addReservedWords('code');
var code = Blockly.JavaScript.workspaceToCode(workspace);

try {
  eval(code);
} catch (e) {
  alert(e);
}
```

上記のコードを実行することで、ブロック達のコードを実行してくれます！
単純に文字列としてコードを取り出し、`eval`で実行しているだけですね！

…ん？
**繋がっていないブロックも実行対象になってしまう？**
**繋がっているブロックだけを実行したい？**

では以下の１行を追加してあげてください！

``` js
workspace.addChangeListener(Blockly.Events.disableOrphans);
```

## ex. Javascriptの実行スピードを調節する
キャラクターの移動をCSSアニメーションで制御している方は困らないのかな？と思いますが、
Javascriptで実現しようとしている方は、**jsの実行スピードの速さに困る**と思います。
私も実際、これの対処に苦労しました（笑）

Google先生はここも公式ドキュメントでフォローしてくれています。

参考：[JS-Interpreter](https://developers.google.com/blockly/guides/app-integration/running-javascript#js-interpreter)

``` js
var code = Blockly.JavaScript.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();

function nextStep() {
  if (myInterpreter.step()) {
    setTimeout(nextStep, 10);
  }
}
```

`Interpreter`のオブジェクトを生成時に実行したいコードを食わせ、
`setTimeout`で1ステップ毎の実行時間をミリ秒で設定できます！
※`run`メソッド実行時に、内部で`nextStep()`メソッドが呼び出されるようです。

ただしJS-Interpreter使用時の注意として、
**独自メソッドを使用する場合は、プロパティにメソッドを読み込ませる必要があります。**

``` js
function initApi(interpreter, globalObject) {
  var wrapper = function(text) {
    return alert(arguments.length ? text : '');
  };
  interpreter.setProperty(globalObject, 'alert',
      interpreter.createNativeFunction(wrapper));

  wrapper = function(text) {
    return prompt(text);
  };
  interpreter.setProperty(globalObject, 'prompt',
      interpreter.createNativeFunction(wrapper));
}
```

上記の例では`alert`と`prompt`というメソッドを読み込ませています。
極力読み込ませるメソッド数は少ない方が保守性は上がると思いますので、注意が必要です！

# さいごに
いかがでしたでしょうか？
少しでもBlocklyを使おうとしている方に届けばいいなと思います！！

ここまでご覧いただき、ありがとうございました！