2007/9/26

一部の編成を選べなくする  VRMスクリプト禅問答
【怎麼生】

レイアウトコンテスト等に応募するレイアウトで、背景として走りっぱなしにしたい編成があります。これをユーザー操作で選択出来ないようにしたいのですが、可能ですか?

【説破】 4.0.7.2

出来ます。基本的な考え方は以下の通りです。

(1) レイアウト上の編成を“選択可能な編成”と“選択禁止の編成”に分けます。
(2) “選択可能な編成”は、アクティブになった時点で自分がアクティブであることをレイアウト変数に記録します。
(3) “選択禁止の編成”は、自分がアクティブとなる操作がおこなわれた場合、(2)で記録した“直前にアクティブであった編成”をアクティブに切り替えます。

このような仕掛けをすることで、任意の編成を選択不可能な状態にすることが出来ます。ただし、この仕掛けの実装にあたっては、VRMスクリプトの仕様上の制約から、一工夫が必要です。

<レイアウトスクリプト>

VarTrain ObjActiveTrain //アクティブな編成を保存する変数

BeginFunc MtdChangeActiveTrain
  Var tmp
  SetEventAfter this MtdChangeActiveTrain2 tmp 1
EndFunc

BeginFunc MtdChangeActiveTrain2
  SetActiveTrain ObjActiveTrain
EndFunc

<選択可能な編成の編成スクリプト>

Var EvtFocusIn
SetEventFocusIn MtdFocusIn1 EvtFocusIn

BeginFunc MtdFocusIn1
  get LAYOUT.ObjActiveTrain this
EndFunc

<選択禁止の編成の編成スクリプト>

VarLayout ObjLayout
getlayout ObjLayout
Var EvtFocusIn
SetEventFocusIn MtdFocusIn2 EvtFocusIn

BeginFunc MtdFocusIn2
  call ObjLayout MtdChangeActiveTrain
EndFunc
最も単純化すると、前述の(1)〜(3)は上掲サンプルコードのように実装することが出来ます。

順序が前後しますが<選択可能な編成の編成スクリプト>から見ていきましょう。ここでは、FocusInイベント(この編成がアクティブになった時点で発生するイベント)でメソッドMtdFocusIn1を実行しています。このメソッドはget命令が1つあるのみで、レイアウトオブジェクトに所属するTrain変数ObjActiveTrainに自分自身(this)を代入しています。

これは、もし、レイアウト上のすべての編成にこのスクリプトが書かれていたとしたら、変数LAYOUT.ObjActiveTrainには常に現在選択されている=アクティブな編成の名前が入っていることを意味します。

表題に掲げた“編成を選べなくする”を実現するには、ユーザーに選択させたくない編成に<選択禁止の編成の編成スクリプト>を組み込みます。FocusInイベントでメソッドを実行するのは前述の<選択可能な編成の編成スクリプト>と同じですが、メソッドMtdFocusIn2は中身が異なります。先ほどあったget命令がなく(=つまり、この編成を選択してもObjActiveTrainの値は変わらない)その代わりにレイアウトオブジェクトのメソッドMtdChangeActiveTrainをcallしています。

最後に<レイアウトスクリプト>、特に<選択禁止の編成の編成スクリプト>からcallされるメソッドMtdChangeActiveTrainを見ていきましょう。

このメソッドが実行されるのは、ユーザーに選択させたくない編成がまさに選択された瞬間です。この編成を選択させたくないのですから、ここでは速やかに他の編成、具体的には変数ObjActiveTrainに記録されている編成=最後にアクティブだった選択可能な編成に、SetActiveTrain命令を使って切り換えれば良いことになります。

が、メソッドMtdChangeActiveTrainにはSetActiveTrain命令はなく、代わりにSetEventAfter命令があるのみです。そしてSetActiveTrain命令は、このSetEventAfter命令によって1ミリ秒後に実行されるメソッドMtdChangeActiveTrain2の中にあります。

今回試して初めて気づいたのですが、VRM4のFocusInイベントは、アクティブな編成の切り替えがおこなわれる直前に実行されるようです。もう少し詳しく言うと・・・

Step1. メニュー選択やF6キー押下、あるいは他のSetActiveTrain命令の実行をVRM4システムが気づく。
Step2. もし、FocusInイベントが設定されていれば、ここで実行される。
Step3. アクティブな編成の切り替えが処理される。

という順序を辿るようです。

イベントドリブン式のプログラミング経験がある方は、あぁ、そういうこともあるよな、とご理解いただけることでしょう。したがって、メソッドMtdChangeActiveTrainの中でSetActiveTrain命令を使っても、Step3.の処理で効果が上書きされるか、あるいはそもそも発動しないみたいです。とりあえず、見かけ上はそのように動いているように思われます。

この制約を回避するには、Step3.以降にSetActiveTrain命令を実行すればよいワケで、それをSetEventAfter命令による1ミリ秒後イベントで実現しています。これは、一般化して言えば「SetEventAfterによって、先行イベントからの連鎖を維持しつつ、callによる単純ネスト構造から離脱する」という手法で、他でもいろいろ応用が利くのですが、まぁ、それについてはまた追々。

最後の方の理屈がわからなくても、とりあえず上掲サンプルコードを然るべくコピー&ペーストすれば表題の動作をするはずですので、レイアウトコンテスト作品等に応用してみてください。なお、FocusInイベントの発動タイミングは製品付属のマニュアルに明記されていないので、今後突然変更されちゃったりするのかも知れません、あしからず。
0

2007/10/3  23:54

投稿者:ghost
> 貨物基地で滞留している「コキ」などはご存知かと…?

えーっと、ピンときません。
何のお話でしょう?
よろしければご教示ください。

> 思想(VRMの真髄)

については別途記事を書きます。

まぁ、結論から申し上げますと、多分I.MAGiCにそういう大層なものはないのです。いや、あるかも知れませんが、それが誰にも伝わらないのであれば、それはないのと同じですから。

そういうワケで、みんなで適当に作っちゃえばいいんじゃないでしょうか。

2007/10/3  20:18

投稿者:漆黒
こんにちはghostさん。なかなか旨く事が運ばないものですね?VRM愛好家が考えている事と製作者(アイマジックさん)が考えている思想(VRMの真髄)がチグハグで…当然、貨物基地で滞留している「コキ」などはご存知かと…?レイヤー機能で簡単に非アクティブに設定出来れば楽なんですがね?いろいろと御教示下さり有難う御座います。

http://vrm.seesaa.net/

2007/10/2  23:18

投稿者:ghost
[F6]による切替は、常に“レイヤーパレット上で次にある編成”へ向かって発生します。この動作をスクリプトからでは変更することが出来ないため、残念ながら漆黒さんがやりたいとお考えのこと=[F6]を繰り返し押すことでレイアウト上の“すべての選択可能な編成”を順に選ぶ、は、現在のVRM4では実現できません。

そういうワケですので、

> 小生の設定が悪いかもしれません

ということはないです。


ちなみに、[F6]キー以外のキーでよければ、選択可能な編成のみを順に切り替えるスクリプトを書くのは簡単です。

ただし、本稿で例示したような“選択可能/不可能な編成それぞれに対応するスクリプトをコピペする”というものにはなりません。レイアウトスクリプト上で、選択可能な編成名を直値で列挙する必要があり、管理が面倒になるのであまりお奨めできません。

2007/10/2  21:17

投稿者:漆黒
ghostさん今晩は。何時もVRMファンに素敵なスクリプトの御提供、感謝しております。早々、取り入れて見ました。
>(3) “選択禁止の編成”は、自分がアクティブとなる操作がおこなわれた場合、(2)で記録した“直前にアクティブであった編成”をアクティブに切り替えます。

確かに選択して欲しくない車両は一瞬表示され最後にアクティブだった選択可能車両にフォーカスされ「1サイクル」は完璧です。しかし、再度「F6」キーで他の選択可能車両を呼び出す事が出来ないのが残念です。(何時までも最終にアクティブ車両が表示される)小生の設定が悪いかもしれませんが…(汗)



http://vrm.seesaa.net/

コメントを書く

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




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