これは Scratch Advent Calendar 21日目の記事です。
こんにちは、id:masawadaともうします。普段は京都クリエイティブワークショップというところでScratchなどを扱ったワークショップの企画運営を行なっている人間です。
ScratchXとは
ScratchXはScratch 2.0の実験版のような扱いで、JavaScriptでブロックを拡張できる(Extensionを作ることができる)のが特徴です。ブラウザのAPIを直接叩くことができるので、Gamepad APIやWebSocketなどによる通信が扱える他、シリアル通信用のインタフェースが用意されているためArduinoなどと連携することもできます。
ExtensionはJavaScriptのURLを入力することで読み込むことが出来ます。このJavaScriptは現状では入力後すぐに<head>
タグの中に<script>
タグでロードされます。一応
このような確認画面が表示されますが、この時点ですでにJavaScriptは読み込まれ実行されているため、不審なExtensionはつかわないよう注意が必要です。
どうやって開発するのか
Extensionの開発は至って簡単です。以下のことをすれば良いだけです。
- ブロックの定義を書く
- ブロックから呼び出される関数の実装
- 定義と関数の登録
以下に概要を記載します。詳しくはGitHub上のWikiをご覧ください。
ブロックの定義を書く
JSONにブロックの定義を書きます。
var descriptor = { "blocks": [ [" ", "%s と言う", "say", "こんにちは!"] ], "menus": {} }
blocks
の中の配列は初項から順番に
- ブロックタイプの設定
- ブロックの文言
- 呼び出す関数名
- デフォルト引数
になっています。
ブロックタイプの設定について
ブロックタイプ*1は以下の5通りです。だいたいの場合は' '(スペース)
を使うことになります。
ブロックタイプ | 意味 |
---|---|
' ' (スペース) |
同期実行 |
'w' |
非同期実行 |
'r' |
同期実行レポータ |
'R' |
非同期実行レポータ |
'h' |
ハットブロック |
レポータ
レポータは値を返すブロックで、ブロックの引数となることができます。(できるはずだけど期待どおりに動かなかったのでこんど調べます、だれか挙動とか教えてください)
ハットブロック
ハットブロックは、「〜キーがおされたとき」のような、処理のスタート用ブロックです。呼びだされた関数の返り値がfalse
からtrue
に変わった瞬間に実行されます。「false
からtrue
に変わった瞬間」なので、一度false
になればまたtrue
になったときに実行されます。
同期実行と非同期実行
JavaScriptは処理を非同期的に実行することが頻繁にあります。非同期処理を行った場合、その終了を待つためのブロックタイプがw
およびR
です。以下の例では、AJAXで外部の処理を取得しています。これらのブロックタイプでは実行する関数の最後の引数としてcallback
が渡ってくるので、これを呼び出すことで処理を継続できます。
ext.get_temp = function(location, callback) { // Make an AJAX call to the Open Weather Maps API $.ajax({ url: 'http://api.openweathermap.org/data/2.5/weather?q='+location+'&units=imperial', dataType: 'jsonp', success: function( weather_data ) { // Got the data - parse it and return the temperature temperature = weather_data['main']['temp']; callback(temperature); } }); };
(コードはGitHubのWikiから引用)
ブロックの文言について
%s
, %n
, %m
のフォーマット指定子で引数を受け取ることができます。%s
は文字列、%n
は数値、%m
は値をリストから選択させることができます。
%m
を用いる場合、予めブロック定義用JSONのmenus
プロパティにmenuName: ['this way', 'that way']
のようなペアを定義しておき、%m.menuName
のように指定することでリストを選択させることができます。
ブロックから呼び出される関数の実装
一つのオブジェクトに関数を登録します。
var ext = { say: function(message) { window.alert(message); } };
ブロックタイプに非同期を指定した場合は引数の最後にcallback
関数が渡されるので、これを呼び出します。
定義と関数の登録
最後に、これらブロックの定義と呼び出される関数を登録します。
ScratchExtensions.register("ブロック群のタイトル", descriptor, ext);
これでScratchXにブロックを追加することができます。
Extensionから叩くことができるAPIについて
ScratchXはあくまでJavaScriptとScratchを接続するインタフェースとシリアル通信用オブジェクトが用意されているだけでその他の環境はブラウザ依存と思います(実際に調べたわけではありません)。実際、Fetch APIを使ったブロックを作った際にはChromeとFirefoxでのみ動きSafariでは動かすことができませんでした。
よって、ブラウザからJavaScriptで叩けるAPI(File APIやWeb Audio APIなど)は一通り叩けるのではないでしょうか。どなたかチャレンジして成功したら教えていただきたいです。
ブラウザに使いたいAPIがあるかどうかはCan I useというサービスで調べることができます。
開発環境を整える
ここからが本題です。ScratchXのExtensionを開発する際に便利なテンプレートの話です。
テンプレートを初期化する
GitHubからプロジェクトをcloneしてリモートブランチの設定を飛ばせば準備完了です。
$ git clone https://github.com/masawada/scratchx-template.git project_name $ cd project_name $ git remote remove origin $ npm i
これで開発環境が整います。
なにができるのか
このテンプレートでは
- JavaScriptの自動コンパイル
- 開発用サーバの立ち上げ
の2つを行うことができます。(後述するディレクトリ構造にある通り)data.jsonにブロックの定義を書き、ext.jsに呼び出される関数を記述するという形になっています。
コンパイルにはbrowserify(watchify)
とbabel
を使用しているためECMAScript2015で記述することもできます。
コマンドと使い方
コマンドは以下の2つが用意されています。
npm run watch
: 自動ビルド用の監視npm run server
: サーバの立ち上げ
前者のコマンドで監視スクリプトを立ち上げることで、src
ディレクトリ以下にあるファイルが更新された際にそれらが自動でコンパイルされます。
後者のコマンドではbrowser-sync
が立ち上がりdist
ディレクトリ以下の静的ファイルを配信します。デフォルトではhttp://localhost:3000
にサーバが立ち上がります。
この状態でScratchXのURLとしてhttp://localhost:3000/main.js
を指定すると、作成したExtensionを読み込むことができます。
ディレクトリ構造とか
テンプレートは以下のような構成になっています。
. ├── README.md ├── dist │ ├── crossdomain.xml ... ScratchXのクロスドメイン設定xml │ ├── index.html ... サーバを立ち上げると出てくるページ │ └── (main.js) ... ビルドするとできるファイル ├── package.json └── src ├── data.json ... ブロックの定義 ├── ext.js ... ブロックから呼ばれる関数の定義 └── main.js ... data.jsonとext.jsをScratchXに登録するスクリプト
まとめ
ScratchXはScratchの世界からコードを書くプログラミングの世界に足を踏み出すのに良いアプローチと思います。また、外部との通信が容易になったことでハードウェアのプロトタイピングをする際に制御をScratchから行うなども可能になり、そのような活用にも期待できます。
是非みなさんもScratchXでおもしろブロックを作って世界に発信していきましょう。
参考にしたサイト/ページ
- Home · LLK/scratchx Wiki · GitHub
- ScratchX 開発 はじめかた - 半空洞男女関係
- ScratchXの開発を爆速で開始できるテンプレートを作りました - 半空洞男女関係
*1:本文章では便宜的にこう呼ぶ、原文ではOp Code