カスタムブロック:ブロックのパラダイム

Blockly を使用するアプリケーションを設計する際は、いくつかのパラダイムを選択できます。ユーザーが必要とするブロックに影響するため、これらの選択は早い段階で検討する必要があります。

設定

Blockly アプリケーションの多くは、実行可能プログラムではなく、構成の記述に使用されます。通常、構成アプリケーションでは、ワークスペース上の 1 つのルートレベルのブロックを初期化することから始めます。そのわかりやすい例が、Blockly Developer Tools の [Block Factory] タブです。

Blockly.Blocks['factory_base'] = {
  init: function() {
    this.setDeletable(false);
    this.setMovable(false);
    this.setEditable(false);
    // etc...
  }
}

Blockly.serialization.blocks.append({'type': 'factory_base'}, workspace);

これにより、ユーザーの構成をすべて保持する、削除不可で移動できないブロックが作成されます。ワークスペースは、現在の構成を確認するためにいつでもシリアル化できます。

このようなアプリケーションでは、ルートブロックに接続されていないブロックを自動的に無効にしたい場合があります。これは、次のように 1 行で実行できます。

workspace.addChangeListener(Blockly.Events.disableOrphans);

シリアル プログラム

Blockly アプリケーションの大半は、シリアルプログラムを作成するように設計されています。ユーザーは、順番に実行されるブロックを積み重ねます。

ワークスペース上のすべての(無効ではない)ブロックがプログラムの一部になります。ブロックのスタックが複数ある場合は、上位のブロックが最初に実行されます。(2 つのスタックの高さがほぼ同じ場合は、左のスタック(RTL モードでは右)が優先されます)。

ワークスペースはいつでも実行可能コードにエクスポートできます。このコードは、クライアント側で JavaScript で実行することも(eval または JS インタープリタを使用)、サーバー側で任意の言語で実行することもできます。

import {javascriptGenerator} from 'blockly/javascript';

var code = javascriptGenerator.workspaceToCode(workspace);

並列プログラム

一部の Blockly アプリでは、ブロックのすべてのスタックを順次ではなく並列で実行する場合があります。たとえば、メロディーに合わせてドラムループを実行する音楽アプリケーションがあります。

並列実行を実装する 1 つの方法は、ブロックごとにコードを個別に生成することです。

import {javascriptGenerator} from 'blockly/javascript';

var json = Blockly.serialization.workspaces.save(workspace);

// Store top blocks separately, and remove them from the JSON.
var blocks = json['blocks']['blocks'];
var topBlocks = blocks.slice();  // Create shallow copy.
blocks.length = 0;

// Load each block into the workspace individually and generate code.
var allCode = [];
var headless = new Blockly.Workspace();
for (var i = 0; block < topBlocks.length; i++) {
  var block = topBlocks[i];
  blocks.push(block);
  Blockly.serialization.workspaces.load(json, headless);
  allCode.push(javascriptGenerator.workspaceToCode(headless));
  blocks.length = 0;
}

ターゲット言語が JavaScript の場合は、allCode 配列を使用して複数の JS インタープリタを作成して同時に実行できます。ターゲット言語が Python などの場合、allCode 配列を、スレッド モジュールを使用する単一のプログラムにアセンブルできます。

他の並列プログラムと同様に、変数や関数などの共有リソースについては慎重に判断する必要があります。

イベント ドリブン プログラム

イベント ハンドラは、プログラムではなく、システムによって呼び出される関数です。これらのブロックは、実行されるブロックのスタックを囲むことも、ブロックのスタックの上にあるヘッダーにすることもできます。

イベント ブロックの上部に「帽子」を付けて、他のブロックと区別できるようにしたい場合もあります。これは Blockly のデフォルトの外観ではありませんが、レンダラ定数 ADD_START_HATStrue にオーバーライドするか(カスタム レンダラ Codelab - 定数をオーバーライド)か、テーマを追加してブロック スタイルに帽子オプションを設定することで追加できます。テーマの一部としてブロックに帽子を設定する方法について詳しくは、こちらをご覧ください。

イベント ドリブン モデルでは、プログラムを起動するためのハンドラを作成することも理にかなっています。このモデルでは、イベント ハンドラに接続されていないワークスペース上のブロックは無視され、実行されません。

イベントを使用するシステムを設計する際は、同じイベント ハンドラの複数のインスタンスをサポートすることが可能かどうかを検討します。