ブロックの生成について

概要

  • この記事ではプログラミングブロックがどのように定義され、生成されているかについて説明します。


プログラミング用のブロックは、ブロックの見た目や操作感を定義するBlockMorph のサブクラスと、ブロックの機能を提供する ScriptableScratchMorph のサブクラスとで実現されています。
ScriptableScratchMorph のサブクラスには、スプライト(キャラクター)用のScratchSpriteMorph クラスと、ステージ(背景)用のScratchStageMorph クラスがあり、ブロックが実行された時の機能を実現するメソッドが定義されています。
例えば ScratchSpriteMorph の forward: メソッドは、スプライトを「○歩進む」という、動きカテゴリのブロックの機能を提供しており、そのブロックが実行された時の処理が定義されています。

ブロックの機能を提供するメソッドと、画面上に表示されるブロックのモーフとは、ScriptableScratchMorph とそのサブクラスのクラス側にある、blockSpecsメソッドにおいて対応づけられます。
下の図を見れば、先ほどの forward: メソッドが、motionカテゴリのmove %n stepsというブロックに対応していることがわかります。

つまり、機能を提供するメソッドを用意した上でblockSpecs メソッドを変更すれば、Scratchにメソッドを追加したり削除できるようになります。

blockSpecsの構造

blockSpecs メソッドはブロックを定義する配列を返し、配列は以下のような要素の並びとなっています。

  • カテゴリを示す文字列
  • ブロック定義を示す配列
  • ブロック間のスペーサーを示すシンボル #-

カテゴリ文字列に続くブロック定義は、別のカテゴリ文字列が現れるまで、そのカテゴリ内のブロックとして扱われます。

カテゴリを示す文字列

カテゴリを示す文字列は普通の文字列ですが、画面に表示されるカテゴリと一致していなければ、どのブロックも表示されません。特にカテゴリに変更を加えていない場合、その文字列は以下のうちのいずれかでなければなりません。
motion, looks, sound, pen, control, sensing, operators, variables
なお、Smalltalkでは文字列リテラルはシングルクオートで囲んで示します。

ブロック定義を示す配列

ブロック定義は3つの要素以上からなる配列で、各要素は以下のような意味を持っています。

  1. ブロックに表示される文字列
  2. ブロックの種類を示す文字
  3. 対応するメソッドセレクタ
  4. ブロックのデフォルトパラメータ(以下続く)

右方向に回転するブロックの定義を例にとると、上の1から4は以下のように対応します。

ブロックに表示される文字列の中に現れる文字%は、そのブロックのパラメータを表します。

ブロックのパラメータのデータ型

パラメータを示す文字%の後には、そのパラメータが取りうるデータ型を表す文字が続きます。上の例では%nとなっていますが、これは数値であることを示しています。文字とデータ型との対応表は以下の通りです。
また、引き数の値をリスト形式で選べるものがあります。表には、リスト情報を生成するクラスとメソッドを載せています。リスト形式でない場合には、そのパラメータを表すクラス名を載せています。
なお、ブロック定義文字列中のパラメータに関する処理を行っているのは、CommandBlockMorph の uncoloredArgMorphFor: メソッドです。

a スプライトやステージの属性のリスト AttributeArgMorph
b 論理値 BooleanArgMorph
c 色(パレット表示あり) ColorArgMorph
C 色(スポイトのみ) ColorArgMorph
d 数値(4方向のリスト付き) ScratchSpriteMorph directionMenu
D 数値(ドラムリスト付き) ScriptableScratchMorph midiDrumMenu
e broadcastメッセージのリスト EventTitleMorph
f 数学関数のリスト ScriptableScratchMorph mathFunctionNames
g 視覚効果のリスト ScriptableScratchMorph graphicEffectNames
h 値を返すセンサーのリスト ScriptableScratchMorph hookupSensorNames
H 論理値を返すセンサーのリスト ScriptableScratchMorph hookupBooleanSensorNames
i 数値(リスト変数のインデックスリスト付) ScriptableScratchMorph listIndexMenu
I 数値(楽器の種類のリスト付き) ScriptableScratchMorph midiInstrumentMenu
k キーボード入力時の文字のリスト ScriptableScratchMorph keyNames
l コスチューム名のリスト ScriptableScratchMorph costumeNames
L リスト変数のリスト ScriptableScratchMorph listVarMenu
m スプライト名のリスト(向く・進む) SpriteArgMorph
M モーター名(A,B)のリスト ScriptableScratchMorph motorNames
n 数値 ExpressionArgMorph
N 数値(鍵盤表示あり) ScriptableScratchMorph noteSelector
s 文字列 ExpressionArgMorph
S 音の名前のリスト ScriptableScratchMorph soundNames
v 変数名のリスト ScriptableScratchMorph varNamesMenu
W モーターの向きのリスト ScriptableScratchMorph motorDirection
x 未使用(おそらくobsolete)
y 削除用のリスト変数インデックスリスト ScriptableScratchMorph listIndexForDeleteMenu

ブロックの種類

プログラミング用のブロックにはいくつかの種類があります。例えばスクリプトの先頭にしか配置できないものや、他のブロックの中にしか埋め込めないものです。
このようなブロックの種類は、1文字のシンボルで表します。シンボルの意味と実際に生成されるブロックのクラスを表で示します。

文字 意味 生成されるブロックのクラス
フラグなし CommandBlockMorph
b 論理値を返す ReporterBlockMorph
c ifやrepeatのように他のブロックを含む CBlockMorph, IfElseBlockMorph
r 値を返す ReporterBlockMorph
s 独自の評価規則を持つ特殊形 CommandBlockMorph
t waitなど時間管理の必要 CommandBlockMorph
E メッセージイベントブロック EventHatMorph
K キーボードイベントブロック KeyEventHatMorph
M マウスイベントブロック MouseClickEventHatMorph
S 開始イベントブロック EventHatMorph

ブロックの種類を表す文字によって、どのブロックを作るかは、ScriptableScratchMorph の blockFromSpec:color: メソッドが決めています。
if 〜もif 〜 else 〜も、同じ種類「c」ですが、このメソッド内で CBlockMorph か IfElseBlockMorph かを変えています。

メソッドセレクタ

生成されるブロックの実際の処理を担うメソッドは、メソッドセレクタの形式(ブラウザのメソッドペインに表示される書き方)で指定します。
記述するメソッドセレクタは、ブロックの文字列に書いたパラメータの個数と、arityが一致していなければなりません。
例えば、文字列を連結するブロックは、join %s %s のような文字列ですが、対応するセレクタは concatenate:with: とarityが2になっています。

ブロックのパラメータの個数とメソッドのarityが一致しない例外があります。それは、timedCommand と呼ばれる一定の時間をかけて実行されるブロックです。
「○秒待つ」や「○拍休む」のようなブロックが該当します。これらのブロックについては、ScratchProcess クラスの applyTimedCommand メソッドが適切に処理を行います。

デフォルトパラメータ

ブロック定義の配列の4つ目の要素以降はオプションで、書かれていてもいなくても構いません。
もし書かれていれば、引き数にデフォルト値が設定されたブロックが生成されます。
先ほどの文字列を連結するブロックの4、5番目の要素は hello と world の文字列ですが、実際のブロックには対応する引き数のデフォルト値として設定されています。

なお、ブロックによっては、動的に引き数の内容が変わるものがあります。
例えば、動きカテゴリで「x座標を○、y座標を○にする」ブロックは、その時のスプライトの位置によって座標の値が変わります。
このように引き数の内容が動的に変わるものは、ScriptableScratchMorph の defaultArgsFor: メソッドで処理されています。