2005/9/5

目指せ完全自動運転(3)−閉塞信号スクリプト  VRMスクリプト禅問答
難易度:☆☆☆

「信号機」なので、VRM4第2号が必要です。
VRM4第2号所収の信号制御用スクロールは、信号1つ当たり灯火の数だけセンサーを必要とするという非効率なものになっています。今回ご紹介するのは信号機に対し、センサー1つだけで閉塞信号の動作を再現できるスクリプトです。まずは現物をご覧いただきましょう。なお、ここでは話を単純化するために三灯式信号機を使う前提で話を進めます。
[センサースクリプト]
//パートナー信号定義
VarSignal ObjPartnerSignal
get ObjPartnerSignal "{信号機の名前}"
//イベント定義
Var EventID
SetEventSensor MtdBlockSystem EventID //・・・@
//
//閉塞イベント
//
BeginFunc MtdBlockSystem
call ObjPartnerSignal StdMtdSignalR //・・・A
EndFunc

[信号スクリプト]
//公開プロパティ
Var StdVarSignalPosition
//初期状態
set StdVarSignalPosition 3
call this StdMtdSignalG
//1つ前の閉塞信号
VarSignal ObjBeforeSignal
get ObjBeforeSignal "{1つ前の信号の名前}"
//
//R現示メソッド
//
BeginFunc StdMtdSignalR
set StdVarSignalPosition 1
SetSignal StdVarSignalPosition //・・・B
call ObjBeforeSignal StdMtdSignalY //・・・C
EndFunc
//
//Y現示メソッド
//
BeginFunc StdMtdSignalY
if>= StdVarSignalPosition 1 //・・・D
set StdVarSignalPosition 3
SetSignal StdVarSignalPosition //・・・E
call ObjBeforeSignal StdMtdSignalG //・・・F
endif
EndFunc
//
//G現示メソッド
//
BeginFunc StdMtdSignalG
ifeq StdVarSignalPosition 3
set StdVarSignalPosition 6
SetSignal StdVarSignalPosition
endif
EndFunc
まずは、充分に長さのあるエンドレスループを作ってみてください。ループの中に適当な間隔を空けて−−−理想的には編成の長さ+α、140mmレール1本を1車両の目安で考えると分かりやすい−−−三灯式信号を配置します。これらの信号にはそれぞれユニークな(他の信号と重複しない)名前を付ける必要があります。とりあえずは「SIGNAL1」から始めて連番を振るのが良いでしょう。
次に、それぞれの信号レールの上にセンサーを1つずつ置いていきます。ここで紹介したテクニックを使ってループをI.MAGiC規格レールで作るのであれば、信号に隣接した部分にセンサーを置くことになります。これらは個々を識別する必要がないので、ユニークな名前を付ける必要はありません。
こうして配置が終わったら、信号とセンサーにそれぞれ上掲のスクリプトをコピー&ペーストしてください。その際、{信号機の名前}/{1つ前の信号機の名前}の部分に、適切な信号機の名前を入れます。「SIGNAL1」から列車の進行方向に向かって2,3,4・・・と名前が付いているとすれば、たとえば「SIGNAL4」信号機を担当するセンサーには「SIGNAL4」と書き込みます。一方、信号機自身のスクリプトには{1つ前の信号機の名前}として「SIGNAL3」を与えます。

さて、こうして出来たレイアウトに列車を走らせるとどうなるでしょうか。
仮に今、「SIGNAL4」信号機を担当するセンサーを列車が踏んだとしましょう。すると@のSetEventSensor命令に従って、メソッドMtdBlockSystemが実行されます。ここではAにあるように、信号オブジェクト変数ObjPartnerSignalが示す信号の、メソッドStdMtdSignalRが実行されます。具体的にはパートナー信号、すなわち「SIGNAL4」のR現示メソッドになります。
信号スクリプト側のメソッドStdMtdSignalRに目を移すと、まずBのSetSignal命令で信号が赤灯火になります。次にCのcall命令で信号オブジェクト変数ObjBeforeSignalが示す信号の、メソッドStdMtdSignalYが実行されます。 具体的には1つ前の信号、すなわち「SIGNAL3」のY現示メソッドになります。SIGNAL4に達した列車は、SIGNAL3の区間を走行してここに至ったはずですから、この動きは、直前に列車が閉塞した(信号を赤にした)区間を開放することを意味しています。
Cのcall命令によって、今度は同じ信号スクリプトが「SIGNAL3」において実行されます。メソッドStdMtdSigalYを見てください。最初にDのifeq命令で自分の灯火色が赤(SetSignalに与える値が1)であることを確認しています。詳細は省きますが、これは複数の編成を同時走行させた場合の誤動作避けです。以下EFは先ほどのR現示メソッドとほぼ同じことをしています。ことなるのは灯火色が黄色であることと、今度は1つ前の信号機のG現示メソッドが実行される点です。ここでいう「1つ前の信号機」はSIGNAL3にとってのそれですから、つまり「SIGNAL2」になります。
この連鎖反応によってSIGNAL2は青灯火となります。念のためにメソッドSetMtdSignalGを読んでみてください。先ほど同様に、誤動作避けのifeq命令と灯火色変更のためのSetSignal命令はありますが、今度は1つ前の信号のメソッドを実行するcall命令がありません。なぜなら、これ以上の連鎖反応は必要ないからです。SIGNAL1は列車がSIGNAL3を通過した時点で青色になっているはずですから。

以上の流れを、前回説明した区間閉塞の考え方と読み合わせてみてください。上掲スクリプトが、まさに区間閉塞を実現すべく書かれていることがご理解いただけると思います。まずは、このスクリプトを組み込んだ実験用のレイアウトを作ってみて、その動作をご自身で確かめてみてください。複数の列車を同じ線上で走らせても、列車が適切な間隔を保って走っている限り信号は正常に動作し続けます。
現時点で達成されたのは、列車の走行に応じて灯火が遷移する信号機だけです。次回以降は、この信号の灯火に応じて列車の動作を変化させる仕組みを解説します。

質問やご要望があれば気軽にコメント欄に書き込んでください。特に「ここの意味がよくわからないのでもっと詳しく」という指摘は大歓迎です、なぜわかりにくいのかの理由が添えられていると特に。
0

コメントを書く

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




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