2006/8/30

駅に止まったときだけ“何か”が怒る  VRMスクリプト禅問答
(前略)
発車チャイムやドアの開閉音はSetEventZeroSpeedとSetEventAfterを使えば、駅に停車するたびに鳴らせますね。
Posted by 45-50s at 2006年08月28日 17:45


(前略)
駅に到着した事を認識するのはセンサーなのか、その他の部品なのかは問題ですが、時間指定をすれば、いちいちキーを押さなくても済みますね。
(後略)
Posted by KSMaster at 2006年08月28日 21:45


に関してお節介を焼いてみよう、と発作的に思い立った。音源の制御自体は(少なくとも、この記事を読んで自分でスクリプトを書こうと思う人にとっては)特別に難しいことではないので、ここでは以下のことを実現する方法について書くことにする。

(1) 編成が停車して指定時間後に「何か」が起きるようにしたい。
(2) ただし、「何か」が起きるのは駅構内の所定の位置に停車したときだけにしたい。つまり、本線上で停車しても「何か」は起きない。

言うまでもなく、引用した二人の会話における「何か」は「音源でドア開閉音を鳴らす」ことになるが、本質的には何であっても構わない。一定時間後の出発でもいいし、車両の切り離しであってもいいし、ログウィンドウで“駅だからって止まってんじゃねーぞ、ゴルァ!”と怒ってもいい。まぁ、最後のは冗談だが、要するにここで言う「何か」は、そういう動作を実現するメソッドであれば何でもいい、というお話ね。その方が応用が利くでしょ?


さて、上記(1)(2)、特に(2)を実現するにあたっては、KSMaster氏が書いているように「駅に到着した事を認識する」ことが必要である。これをどうするかだが、次のように考えてみた。

・2つのセンサー[センサーA]と[センサーB]を用意する。
・[センサーA]は「これ以上手前に止まったら駅停車とはみなさない」地点に置く。列車が(どんな速度であろうと)ここを通過したとすれば、それは駅停車の「可能性が生じた」ことを意味する。
・[センサーB」は「これを越えて止まったら駅停車とはみなさない」地点に置く。つまりオーバーランの限界点。ここを通過したとすれば、それは駅停車の「可能性がなくなった」ことを意味する。

察しの良い人は、ここまで読めばもう自力で要件(1)(2)を満たすスクリプトを書くことが出来ると思う。読むのを止めてただちにVRM4を起動するように。未だ具体像が浮かばない読者諸兄のために以下にサンプルコードを示す。
[センサーAスクリプト]
Var SensorEventID
SetEventSensor 編成検知 SensorEventID

BeginFunc 編成検知
VarTrain ObjTrain
GetSenseTrain ObjTrain
call ObjTrain 駅停車準備
EndFunc

[センサーBスクリプト]
Var SensorEventID
SetEventSensor 編成検知 SensorEventID

BeginFunc 編成検知
VarTrain ObjTrain
GetSenseTrain ObjTrain
call ObjTrain 駅停車準備取消
EndFunc

[編成スクリプト]
Var StopEventID
Vat AfterEventID

BeginFunc 駅停車準備
SetEventZeroSpeed 停車完了 StopEventID
EndFunc

BeginFunc 駅停車準備取消
KillEvent StopEventID
EndFunc

BeginFunc 停車完了
SetEventAfter {オブジェクト} {何かをするメソッド} AfterEventID {経過時間}
EndFunc
と、こんな感じ。例によって出先で書いているのでバグってたらゴメン。

センサーA/Bのスクリプトは至極簡単で、それぞれ検知した(センサーの上を通った)編成のメソッド駅停車準備/駅停車準備取消をcallするだけ。これが前述した、駅停車の「可能性が生じた」「可能性がなくなった」に対応している。

編成スクリプト側の当該のメソッドは、変数StopEventIDを使う表裏の処理になる。つまり、駅停車準備ではSetEventZeroSpeed命令によって停車時に発生するイベントを設定し、駅停車準備取消ではKillEvent命令でこれを無効化している。つまり、センサーAを通過した列車が、センサーBに至る前に停車すればメソッド「停車完了」が実行れるが、センサーBを通過してしまうとこのイベントが解除されてしまうので、メソッド「停車完了」は実行されない。言うまでもなくこれが、本線上で停車しても「何か」は起きない、に対応している。

メソッド「停車完了」では、停車してすぐにドアが開いたりその他のことが起きるのはアレゲなので、SetEventAfter命令で指定時間待ってから「何か」を起こすようにしている(これは必須ではない)。{オブジェクト}{何かをするメソッド}を、あなたが起こしたい「何か」を実現するそれに書き換えれば実装完了。

この方法のメリットは、編成がその駅に停車するのか通過するのかを、まったく意識する必要がない点にある。逆に言うと、この方法であれば、編成の走行自体をまったく別の方法(たとえば拙作gws/1.0自動運転スクロールなど)で自動化していたとしても、変数名・メソッド名が衝突しない限りはお互いに影響することなく合わせての組み込みが可能だ。

ここに示したのは基本的な骨組みだけで、もう少し改良の余地はある。たとえば、メソッド「停車完了」が実行されてからユーザーが手動操作で編成を出発させると、列車が動きながらドアが開く音がする、という危険な状態に陥る。これを防ぐには、列車の出発に連動して変数AfterEventIDをKillEventするとか、あるいは、SetEventZeroSpeedと同時にSetFixVolumeModeで出発を封じるといった対策が必要。

また、StopEventIDをKillEventすると同時に、別のメソッドを実行するSetEventZeroSpeedを仕掛けてやれば、駅以外のあらぬ位置に停車した際に“どこに止めてんだと、ゴルァ!”と怒ることだって出来る。っつーか、こっちの方が正しいな、メッセージとしては。
0

コメントを書く

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




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