2006/7/9

編成を解結する話・その1  VRMスクリプト禅問答
VRMスクリプト会議室のメッセージNo.287から始まる話題(質問者はKSMaster氏)について、かのスレッドに書ききれなかった補足と派生の話題を少々。なお、以下はアップデータ4.0.3.5に関する知見につき、数百カに修正が加わるという噂の4.0.4.0では挙動が変わっているかも知れない。

*     *     *

まず、編成分割を試みるユーザーが必ず一度は躓きそうな話題から。
Uncouple命令の第二引数には編成オブジェクト変数を与える。これにより、編成分割によって新たに生まれる編成への参照がこのオブジェクト変数に記録される。つまり、
VarTrain TmpTrain
Uncouple {切り離し位置} TmpTrain
とした以降は、
call TmpTrain {メソッド名}
とすることで、新たに生まれた側の編成のメソッドを実行できる、ということになる。
いや、むしろ「こうする以外、新たに生まれた編成のメソッドを実行する手段はない」と言った方が正しい。VRMビュワー実行中、編成はその名前ではなく、ビュワー起動時に名前と一対一で割り当てられたID(コンパイラがおこなうのでユーザーが任意に指定することも、知ることもできない)によって識別されている。厳密に言うと、そう見える。
従って、ビュワー起動時に存在していない編成=分割によって生まれる編成に対しては、ユーザーが名前を参照することによっては(たとえビュワー上ではその名前が「編成_1」になることが事前にわかっていても)制御することが出来ない。唯一、分割によって生まれる編成の「ID」を知る方法が、Uncouple命令の第二引数ということになる。


さて、製品付属のスクリプトマニュアルには、
レイアウト(オブジェクト)に作成したグローバル変数に保存すると、広範囲で参照できるだけでなく分割の有無を判断するワークとしても利用でき便利です。

VRM4スクリプトマニュアル/Uncouple命令の頁より
()内は筆者補足
とある。これを読めば、おそらく十人中九人は、以下のいずれかのコードを書くのではないだろうか。すなわち、
Uncouple {切り離し位置} LAYOUT.{編成オブジェクト変数}

  または

VarLayout ObjLayout
getlayout ObjLayout
Uncouple {切り離し位置} ObjLayout.{編成オブジェクト変数}
という具合に。書き方は異なるが、やろうとしていることは同じで、レイアウトオブジェクトでVarTrain命令で宣言した編成オブジェクトに、Uncoupleの結果生まれる編成IDを取得しよう、という作戦である。
が、結論から言うと、いずれも正しく動作しない。上の例(LAYOUT参照)では分割は実行されるがオブジェクト変数に新編成が取得されない。下の例では分割すら起こらない。ビュワー起動時にエラーにならない、にもかかわらずである。

※ 厳密に言うと、マニュアルの記述を信じる限りレイアウトオブジェクト所属の変数にアクセスする際は、上が正しい記述であり、下は間違っている(コンパイルエラーにならないだけ)。

ちなみに、LAYOUTではなく他のオブジェクト(センサー等)所属の変数に書き出そうとしても結果は同じだったりする。ではどう書くのが正しいのか。答えはこう。
VarTrain TmpTrain
Uncouple {切り離し位置} TmpTrain
get LAYOUT.{編成オブジェクト変数} TmpTrain
つまり、一旦自分自身(分割される編成)に所属するオブジェクト変数に書き出してからget命令でレイアウトオブジェクト側の変数に運ぶ、という手順を要する。

さて、ここでVRM入道の熱心な読者であれば、この件を思い浮かべるのではないだろうか。マニュアルをよく読むと、Object.Variable形式を受け入れるのは「変数」と書いてあるところだけだ、とされている。リンク先のエントリは、これとオブジェクト参照を区別して考える必要がある、という話だったワケだ。
で、実はUncouple命令の第二引数は「変数」ではなく「Train変数」だとマニュアルには書いてある。つまりVarTrain命令で宣言される編成オブジェクト変数のことだが、言葉通り解釈すれば「変数」ではないので、Object.Variableはそもそも仕様上無効なのかも知れない。
で、気になったので、マニュアルで「Train変数」が引数に指定されている命令すべて(GetCameraTrain, GetSenseTrain, GetTrainOnTurntable)について、LAYOUT.{オブジェクト変数}への書き出しが正常に動作するか実験してみた・・・ら、ちゃんと動作した。

(i д i)

というワケで、この件は仕様なのかバグなのか判然としない。まぁ、とりあえず編成分割制御に挑戦する人のために以上の知見を公開しておく。で、何か更に詳しいことがわかったら、仮説でもいいから教えてね。
0

2006/7/8  21:03

投稿者:ghost
多分違う。>天狗亭殿

と言うのも、実は例えばGetSenseTrain命令を含むメソッドをセンサー以外のイベントから強引に駆動すると(つまり列車の検知に"失敗"すると)Train変数の値は同じよう0になるのだ。

この観点からは、Train変数のポインタを引数とする命令の内部動作は一致しているように見えるワケ。むしろ怪しいのはUncouple命令のみ問題の引数が第二パラメータである点で、その解釈ルーチンに穴というか、有り体に言うと「手抜き」があるんじゃないか(Object.Variableの解釈をおこなう解釈ルーチンをこの文脈で利用しようとすると何らかの手間が必要で、それを省いたか、あるいは忘れた)ってのがボクの読みなんだけど。

2006/7/8  19:19

投稿者:天狗亭
Scriptマニュアルにおいて、
"Train変数2で新しく生成された編成を受け取ります。切り離しに失敗した場合は、この変数に0がセットされます。"
とあるように、"失敗した場合"には、Objectではない"0"を格納する為にこのような仕様になっているのではないかと。(そんな単純なこっちゃない?)

因みにこの"失敗した場合は、この変数に0がセット"は、おいらのレイアウトでも、エラー判定として使用してます。(デバッグのとき便利。)

http://blue.ap.teacup.com/tengutei/

コメントを書く

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




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