Rosso Laboratory

Rosso Laboratory

主に鉄道模型シミュレーター(VRM)などの仮想鉄道アプリを扱うブログです。またHDR写真の記事も書いています。

Pythonで単線閉塞両方向運転を構築する(後編)


では3つの項目を詳しく見ていきましょう。

①共通ステータスのコマンドには偽物がある(^_^;)
SetStatusDataIntやGetStatusDataInt等のステータス関連のコマンドには2種類あったのですが、レイアウトオブジェクトのコマンドの方を見て「共通ステータスのコマンド見っけ」と思い、その後部品共通のコマンドにもSetStatusDataIntやGetStatusDataIntがあったので「センサーでも同様に使えるな」と思ったのです。これが間違いで、部品共通のコマンドの方は共通ステータスではなく部品ステータスというよく分からんものを読み書きするものでした(^_^;) なので、レイアウト同様にセンサーでもobj.SetStatusDataInt("ステータス名",整数)と書いていたのですが、センサーではvrmapi.LAYOUT().SetStatusDataInt("共通ステータス名",整数)のように書く必要があったのです。紛らわしいですね(^_^;) これが「止まるべきところで列車が止まらず」の原因でした。

②自動センサーの向きは自動ではない(^_^;)
自動センサーは昔のセンサーと違って向きがあり、普通に使うならば有効な方向と無効な方向は自動で認識されるのですが、これがスクリプトでは自動ではなかったのです(^_^;) 向きはあるのですが順方向で使うならば方向を得るGetForwardを使い、
    elif ev == 'catch':
        f = obj.GetForward()
        if f == 1:
というスクリプトを書いておく必要がありました。これが「止まってはいけないところで列車が止まる」原因でした。

③同じ関数内でも違うイベント間ではローカル変数は使えない(^_^;)
これでいけるかと思いきや今度は再出発してくれないという問題が発生しました。原因はローカル変数のスコープでした。まず'catch'イベのGetTrainで編成「train」をゲットし停車させます。その20秒後'after'イベ内でSetEventTimerを5秒おきに実行。'timer'イベ内で共通ステータスを見て条件が整ったら「train」を出発します。ところが'catch'イベでゲットした「train」は'timer'イベで使おうとした時にはもう居ないのです。同じdef(関数定義)内だからローカル変数でスコープは有効だと思っていたのですが、角卓氏著「「鉄道模型シミュレーターNX」で学ぶPythonプログラミング入門」P.38によると「イベントが発生するたびに「vrmevent関数」が呼ばれますが、関数内で定義した「ローカル変数」は、その都度初期化されてしまいます。」とのことで、正にここに原因がありました。よって「train」はグローバル変数にしておく必要があったのです。(角氏によるとグローバル変数よりもDict型メンバー変数を使う方が良いとのことですが、まだDict型がよく分からないもので(^_^;))

ということで、これで大体予定通り動き出したのですが、ずっと動かし続けていると再出発が早すぎて対向列車に邪魔されて止まるような状態もまだ発生しており、もう少し考える必要がありそうです。しかし、Pythonスクリプトでやる方が簡単とまでは言いませんがスマートに出来るような気はしますね。参考までにセンサーに書き込んだスクリプトの1つを掲載しておきます。

#海→信号所センサー(第3センサー)
#OBJID=xx
import vrmapi
def vrmevent_xx(obj,ev,param):
    if ev == 'init':
        global train3
        global evid3
    elif ev == 'broadcast':
        dummy = 1
    elif ev == 'timer':
        if param['eventUID'] == 10002:
            singou = vrmapi.LAYOUT().GetStatusDataInt("信号所山行")
            yama = vrmapi.LAYOUT().GetStatusDataInt("山側")
            if singou == 1:
                if yama == 0:
                    train3.AutoSpeedCTRL(200.0,1.0)
                    vrmapi.LAYOUT().SetStatusDataInt("信号所山行",0)
                    obj.ResetEvent(evid3)
    elif ev == 'time':
        dummy = 1
    elif ev == 'after':
        if param['eventUID'] == 10003:
            evid3 = obj.SetEventTimer(5,10002)
    elif ev == 'frame':
        dummy = 1
    elif ev == 'catch':
        f = obj.GetForward()
        if f == 1:
            train3 = obj.GetTrain()
            vrmapi.LAYOUT().SetStatusDataInt("海側",0)
            yama = vrmapi.LAYOUT().GetStatusDataInt("山側")
            if yama == 1:
                train3.AutoSpeedCTRL(450.0,0.0)
                vrmapi.LAYOUT().SetStatusDataInt("信号所山行",1)
                obj.SetEventAfter(10,10003)

PVアクセスランキング にほんブログ村