2006/4/23

繰り返し処理の書き方  VRMスクリプト禅問答
【怎麼生】
ある動作を一定間隔で繰り返したい場合、どのようにスクリプトを書くべきですか?

【説破】4.0.3.3
大きく分けて二通りの方法があります。
第一には、SetEventTimer命令を使う方法。第二には、SetEventAfter命令を使う方法です。それぞれ「繰り返しの止め方」に特徴があり、これをうまく使い分けるとスッキリとしたスクリプトを書くことが出来ます。

例えば「あるキーを押したら繰り返しを止める」といったケースではSetEventTimer命令を使うのが有利です。逆に「繰り返しが一定回数に至ったら止める」といったケースではSetEventAfter命令を使った方が有利です。


SetEventTimer命令は、一定間隔で指定したメソッドを実行し続けるイベントを設定します。この繰り返しを止めるには、SetEventTimer命令を実行した際に変数に取得されるイベントIDをKillEvent命令に与えます。以下がその例です。
//繰り返し処理の設定
Var LoopID
SetEventTimer Object MtdLoop LoopID {ミリ秒}
//このサンプルでは繰り返し処理の中身(MtdLoop)を省略しています

//繰り返し停止処理の設定
Var KeyID
SetEventKey this MtdStopLoop KeyID {キー}
//繰り返しを止めるメソッド
BeginFunc MtdStopLoop
KillEvent LoopID
EndFunc
冒頭のSetEventTimer命令によって、{ミリ秒}感覚でのメソッドMtdLoopの繰り返し実行が開始されるとともに、変数LoopIDにイベントIDが取得されます。
これを停止するには、この変数LoopIDを使ってKillEvent命令を実行します。この例ではKillEventをキーイベントで実行されるメソッドの中に書いていますが、その他のイベントであっても構いません。
ここでは敢えて繰り返し実行される中身のメソッドMtdLoopを書いていませんが、これはそれが繰り返し実行を止める方法と関係がないからです。逆に言うと、繰り返しおこなわれる処理自体と繰り返しを止める条件の間に関係がなく、まったく別の要因(キーを押す、や、編成が停止する、といったイベント)をキッカケに繰り返しを停止したい場合は、この書き方が有利である、ということになります。
これは、KillEvent命令は、繰り返し処理(に限らず、イベントに設定されたメソッドの中身)とはまったく無関係に実行できることによります。より一般化すると、繰り返し処理から見て「外部の要因」が停止条件になるのであれば、その外部の要因を別途イベント設定し、そこでKillEventするというのが定石になります。

逆に、繰り返し処理から見て「内部の要因」が停止条件になる場合、SetEventAfter命令を使う方が有利です。ここで言う内部の要因とは、その繰り返しの回数のように、繰り返し実行されるメソッドの中で変数を参照した方が判断しやすい条件、を意味しています。以下がその例です。
//準備
Var LoopID
Var VarLoop
Var VarCount
set VarLoop {繰り返したい回数}
set VarCount 0
//繰り返しメソッド
BeginFunc MtdLoop
//
//まず、繰り返し実行すべき処理をここに書く
//ここから他のメソッドをcall/CallCarしても良い
//
add VarCount 1
if< VarCount VarLoop
SetEventAfter this MtdLoop LoopID {ミリ秒}
else
set VarCount 0
endif
EndFunc
この繰り返し処理を開始するには、他のメソッドからcall {Object} MtdLoop する必要があります。
繰り返し処理の本体となるメソッドMtdLoopの中で、繰り返し実行した回数を変数VarCountで数えている点に注目してください。これを繰り返したい回数を示す変数VarLoopと比較(if<命令)し、まだその回数に至っていない場合のみ、SetEventAfter命令を使って指定時間後にもう1度自分自身を実行するようにイベント設定しています。
もし、その回数に至っていた場合(else命令以下)は、もう一度同じ繰り返し処理をおこなう場合に備えてVarCountを0に戻しています。ここではSetEventAfterをしないので、結果的に繰り返し処理が終了することになります。
この例では「繰り返し回数」を内部要因の例として挙げていますが、繰り返し停止の条件は、繰り返し実行されるメソッドの内部から変数で参照できるものであれば何でも構いません。
たとえばこちらで紹介しているような「ある信号の灯火色(GetSignal命令で得られる数値)」が青(6)になるまで待つ、というのも、同じ考え方によるものです。

*     *     *

以下、余談ですが。
特にSetEventAfterを使うパターンについては、メソッドから自分自身を実行する形になるためこの問題に抵触するのでは?と訝る真面目な方がおられるかも知れません。が、結論から言うとその心配はありません。
あの問題は、call命令に「他のメソッドを実行してから戻って来い」という意味があるから起きる問題です。これを繰り返すと、callの連鎖が積み上がっていくことになります。
これに対してSetEvent〜命令は、それが実行された時点でイベント処理をVRMシステムに預けてしまいます(ある意味、変数に取得されるイベントIDはその「預かり証」のようなものです)。SetEvent〜を含むメソッドは、後の処理はVRMシステムに任せて自分自身は正常に終了するため、連鎖して積み上がる、ということが起きません。
0

コメントを書く

この記事にはコメントを投稿できません




teacup.ブログ “AutoPage”
AutoPage最新お知らせ