2006/7/10

編成を解結する話・その2  VRMスクリプト禅問答
昨日の続き。

*     *     *

まず、編成を連結した場合の編成スクリプトに関する基本をおさらいしておこう。下のような状況を想定して欲しい。

例:

 [編成A(機関車)] → 連結 → [編成B(客車)]

イメージし易さを優先して(機関車)(客車)と車両の見た目上の種別を記入しているが、これはVRMの動作にはまったく関係ない。本質的な要素は「走行している編成Aが、停車している[編成B]にぶつかる」である。
連結が起きると、[編成A]はビュワー上からは消える。丁度、[編成B]に吸収されたような感じだ。この動作は上に示したような(機関車)が(客車)を連結するという一連の流れからすると(操作主体が(客車)になるのは不自然という意味において)直感に反するが、まぁ、これはVRMがこういう仕様なのだから仕方がない。

余談となるが、上の例で[編成A]と[編成B]が共に走行していた場合(現実の運用上はあり得ないが)レイヤーパレット上でより下に位置する編成側に吸収されるようである。あなたが完璧主義者であり、ユーザーの介入によって編成連結時の挙動が変わることを何としても避けたいと願うのであれば、連結を待つ編成側でSetFixVolumeMode,SetEnableHomeKey命令を実行し、操作を禁止する必要がある。まぁ、そこまでせんでもいいとは思うけど。

このような次第であるから、連結後の編成をスクリプトで操作したい場合、その編成スクリプトは[編成B]側に書いておかなければならない。編成連結イベント(SetEventCouple命令でハンドルできる)も[編成B]側で発生する点に注意が必要である。「連結イベントはぶつけられた方で起こる」と覚えておけば良いだろう。

さて。
ここでひとつの疑問が生じる。[編成A]を[編成B]にぶつけた場合、[編成B]の編成スクリプトがそれ以降も有効となるのはわかった。では、[編成A]に書かれている編成スクリプトはどうなってしまうのか。結論から先に言うと、実は[編成A]の編成スクリプトは連結後も有効なのだ。


これは以下のようなサンプルコードを書いて実験してみればすぐにわかる。

[レイアウトスクリプト]
Var KeyID
SetEventKey 編成A MtdTest KeyID z

[[編成A]スクリプト]
BeginFunc MtdTest
DrawMessage "Test!!"
EndFunc
こう書いておいてビュワーを起動し、まず[編成A]を適当な編成にぶつけて連結する。ビュワー上から[編成A]が消えていることを確認した後、zキーを押してみよう。すると消えたはずの[編成A]のスクリプトが実行され、ログウィンドウには“Test!!”と表示される。

で、これの意味するところであるが。

第一に。編成の連結によって「[編成A]が消える」というのは文字通りの意味ではない、ということ。単に、ビュワーの操作インターフェイス上で[編成A]と呼ばれているそれと、ビュワーの内部動作において起動時に[編成A]と呼ばれていたそれの関係性が途切れるだけ、これがVRMにおける「編成が消える」の意味である。

第二に。であるがゆえに、ビュワーのメモリ内部には起動時にコンパイルされた[編成A]のスクリプトが厳然と残っており、他オブジェクトからcallすることも可能である、ということ。連結前と異なるのは、最早これらのスクリプトに含まれる編成の動作制御命令(SetVoltage等)を実行しても、その影響を受ける編成は[編成B]に吸収されてしまっているので存在しない、という点である。

第三に。この結果、不用意に[編成A]スクリプトのメソッドに対するイベントを残したまま連結をおこなうと、最悪ビュワーを異常終了させる原因となるということ。明らかにヤバいのはSetActiveTrain命令を含むメソッドで、この命令に消失済みの編成オブジェクトを与えると十中八九ビュワーが異常終了する。従って、理想から言えば[編成A]を連結するまでに、[編成A]内部のイベントはもちろんのこと、外部から[編成A]のメソッドを実行するイベントも、すべてKillEventしておいた方がよい、ということになる。前者は[編成A]でKillAllEventすれば済むが、後者はそれぞれイベントを仕掛けた側のオブジェクトでKillEventしなければならないのが面倒だ。それが嫌なら、連結して消える運命にある編成に対しては、外部から固定的な(GetSenseTrain等に拠るのでない)メソッド呼び出しをしないのが正解だろう。

まぁ、一般的なユーザーがここまで気にする必要もないとは思うが、何かの参考になればと思いまとめてみた。

ちなみに、最もヤバいのは、上のまとめが正しいとすると、連結・分割を繰り返せば繰り返すほど、ビュワーのメモリ空間内には利用されなくなったコンパイル済みスクリプトコードのデッドコピーが溜まっていく、ということのような気もする。それが現実的に問題になるほど長時間ビュワーを稼動させ続けるというシーンも考えにくいが、こういう利用だって想像は出来るワケだし。それとも、ガーベージコレクションに相当するロジックが何らかの形で実装されているのだろうか。それはそれで不安だな(笑)。
0

2006/7/20  7:51

投稿者:ghost
補足:
http://silver.ap.teacup.com/ghost/699.html で得られた知見が真であれば「後者はそれぞれイベントを仕掛けた側のオブジェクトでKillEventしなければならないのが面倒」との記述は誤である。

コメントを書く

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




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