サブルーチンのことだ。ブロック作成時にはいろいろなオプションがあるのだけど、「画面を再描画せずに実行する」にチェックを入れる。再描画とは、つまり垂直同期だ。ブロック中には垂直同期待ちをしない、と指定できる。方法としては非常に簡単だ。以降の説明では、この技法を「高速化」と呼ばせてもらう。注意点として、垂直同期待ちをしない、というのはシステムに処理を戻さない、という意味なので、イベントも発生しない、ということを忘れてはならない。メッセージを送ったり、クローンを生成することは出来る。ブロックの中にいる限り、そのメッセージを他のプログラムが受け取ることはないし、「クローンされた」イベントも起こらない。いうことか、次に詳細に述べよう。▼クローン処理ループ内でクローンを使って多数のキャラクターを作り出していたとしよう。クローンされたキャラクターを好きな位置に配置するために、座標をグローバル変数で渡していたとする。「クローンされた」イベントが起きると、クローンは座標をグローバル変数から取り出し、自分自身の位置を変更する。グローバル変数を書き換え、クローンを生成したとしても、ループ末尾ごとにシステムに処理は返され、「クローンされた」イベントが起きるので問題なく動作する。ここで、多数のキャラクターを作るのに時間がかかるので、高速化したとする。ループ末尾になってもシステムに処理は帰らず、次々とグローバル変数を書き換えながらクローンを作り出す。すべての処理が終わり、ブロックが終了した後に、まとめてすべての「クローンされた」イベントが実行される。最後のグローバル変数の位置に、作り出したすべてのクローンが移動してしまう。高速化するためのオプションを入れただけでプログラムは変えていないのに、さっきまでは起きなかったバグが起きる。単純なゲームを作る程度なら高速化する必要はない。普通はクローンとループはセットになっているだろうし、何も気にせずに作っても、結構うまく動く。内部構造を理解しなくてはならない。プログラムはスプライトに属するもので、そのスプライト自身の挙動を記述する。他のスプライトの挙動を制御することは出来ない。クローンは例外的な命令で、自分自身をクローンするだけでなく、指定したスプライトをクローンすることもできる。ここで、スプライトを指定してクローンすると、そのクローン後の挙動を制御することが難しい。出現位置を変えたり、何らかのパラメーターを渡すには、上に書いたようにグローバル変数を介在させる必要があるだろう。高速化で悩むことになる。「自分自身」のクローンで事足りるのであれば、こちらの方が多くのことを制御できる。いうのも、クローンは、クローン命令時点でのクローン元のローカル変数内容をコピーして引き継ぐからだ。グローバル変数を介在しない。「クローンされた」が実行されるまでのタイムラグもない。命令実行時点でパラメーターを受け渡す、唯一の方法だ。自分自身のクローンで何もかも済ますことはできない。パラメーターを受け渡したい、という唯一の理由で、それ以外のすべてのプログラムも受け継ぎ、全く挙動が違うのに処理を振り分ける...なんていうややこしいことをする必要はない。挙動が違うのであれば、全く違うスプライトにしたほうがいいだろう。その分パラメーター受け渡しがややこしくなるかもしれないけど、全体が複雑化するよりは簡単だ。パラメーター受け渡し用に、リストを用意するといいだろう。「追加」すると、リスト末尾にデータが入る。これで値を受け渡しすれば、多数のクローンが一気に作られても問題は出ない。#「クローン」命令の発行順と「クローンされた」イベントの起こる順が一緒である保証はないので、種別の違うスプライトをクローンする際には、違うキューを用意しておいた方が無難。先に書いたように、一つのスプライトですべてを済ませてしまえば、キューが多数になるような複雑さは防げる。どちらにするか、自分の良いと思うバランスを考えてプログラムするしかない。▼プログラムテクニック動作詳細としては、以上だ。いう言語処理系が、ゲーム作成に必要な技術を自然な形で取り込んでいるのがわかると思う。いえ、やっぱり初心者向けの言語なので、すでにプログラム経験が深い人には使いづらいかもしれない。いうサブルーチンは作れるのだけど、返り値は戻せないし、ローカル変数も使えない。一応引数は渡せて、それはローカル扱いになるのだけど、この引数は参照のみで変更禁止。やるような、引数を使ったローカル変数定義テクニックとかは使えない。オブジェクトは作れる。用語的なオブジェクトと若干の混同が見られる。オブジェクトは、必ずスプライトなのだ。スプライトだから必ず画面表示用の画像が付くし、暗黙の内に座標などの変数が定義されている。画面から「隠す」ことは可能だし、いらない機能は無視すればいい。オブジェクトなのだから、その内部だけで使える変数も定義できる。サブルーチンではローカル変数が作れないが、オブジェクト内でローカル変数が使えるのだから、良しとしよう。オブジェクト間ではメッセージを介して通信ができるが、先に書いたようにメッセージ送信は即座に行われるわけではない。ゲーム用なので、「次の画面までに解決できれば良い」程度のことは、メッセージで処理できる。今回コラムスを作ったのだけど、フィールドを一つのオブジェクトとして扱おうと試みて、断念した。結果として、フィールドは配列(リスト)構造になった。落ちてくる宝石を操作するオブジェクトでは、このフィールドを覗きながら、積み上がっている宝石に当たらないように操作を行う。落ちきったら、ゲームの流れを制御するオブジェクトが、フィールドを調べて消える宝石を消す。宝石が消えたときは、「消えたよ」というメッセージが送信される。このメッセージは、表示されている宝石すべてが受け取ってしまう。宝石は、メッセージをきっかけとして、各自が自分に対応するフィールドの中を調べる。自分のいる位置の宝石が消えていたら、消えるアニメーションを実行して消滅する。「フィールド」の扱いがいろんなオブジェクトに分散していて面倒くさい。オブジェクト指向の美しさなんて全くない。ダメだ」と言っているのではないよ。泥臭い方法をとったけど、ちゃんと作りたいゲーム作れたもの。世の中には結構ダメな環境があって、不満が出たら「あきらめる」しか選択肢がない場合もある。ちなみに、不満が出ない環境というのは存在しない。泥臭い方法を許容する。教室をやっている「ロジックラボ」さんが、このページ内容を子供向けに興味を持てる形に置き換えて、漫画で描いてくださっていました。そこで指摘されるまで気づいていませんでしたが、画面描画に関与するような変更がない限り、ループ末尾でシステムに処理を返すようなことはしない、とのこと。確かに、実験してみるとその通りでした。「リスト」の処理が微妙で、ループ中にリストをいじった時、デバッグ用にリストを表示していると、表示更新のために垂直同期待ちします。デバッグ時でないと垂直同期待ちしません。この日記を書く前、ゲーム作成時にどうも同期タイミングが理解できず、「デバッグのために」リスト表示したりしていたので、ループ末尾は常に処理が戻るのだと勘違いした模様。動作をあまり知らないので、調べて整理したかった、という動機です。関してはまだまだ素人。ちなみに、変数は画面に表示していても、垂直同期を引き起こさないようです。一貫性がないけど、変数は頻繁に書き換えるものなのでいちいち待ち時間を発生しないほうが良い、という判断なのでしょう。追記もう一本ゲームを作ってみてます。近いうちに公開できると思うけど、システムに処理を返すタイミングがよくわからなくなって困っています。状況次第で、画面描画しないループでも、システムに処理を返すことがあります。「高速化」オプションをつけているブロックの途中で、システムに処理を返してしまうこともあります。今作っているゲームでは、面クリアして特定の面に差し掛かったところで、後者のバグ(?)が出ることが多い。バグが出るわけではないけど、ある程度再現性があるので、特定条件でバグが出るのだと疑っています。一連の無限ループスクリプト内でブロックを呼び出している場合、繰り返し呼び出されるブロックが、常に高速かオプションが無視されます。いうことは、このバグは「ブロック呼び出し」に付随するのではなく、そのブロックを呼び出すスクリプトのスレッドに付随するようです。#面クリア時にスレッドを終了し、次の面で再度スレッドを起動する、というつくり方をしている。バグが出た面は、ずっとスレッド内で呼び出されるブロックの高速化オプションが無視される。(ゲームにならなくなってしまうので、クリアして次の面でどうなるかは不明)スクラッチのタスクスイッチはまだまだ謎が多いです。申し訳ありませんが、現在意見投稿をできない状態にしています。