2007/4/28

ゆゆぽん☆退避/追越列車とか作っちゃうかMona-(4)−分岐ポイントを切り替える  VRMスクリプト禅問答
<<前回へ

今回は、課題(1)-2“(1)-1の結果に従ってポイントを切り換える”についてです。下線部(1)-1の結果とは、前回、センサースクリプトにおいて編成オブジェクトから取得した「編成の性格(追越/退避列車のいずれか?)を示す値」です。

まず、大まかに何をしなければならないか、列挙してみましょう。

[d'] センサーで取得した値を、ポイントのグローバル変数に代入する。
[e] センサーからポイントの編成判別をおこなうメソッドを実行する。
[f] センサーから得た値からポイントを正/反位のどちらにするか判別する。
[g] ポイントを切り替える。

[d']は、前回の[d]を言い換えたもので、基本的には同じことです。[e]と合わせてミニマムなサンプルコードを以下に示します。なお、センサースクリプトは前回してしたサンプルコードに追記したもので、前回既に示されていた部分は文字色を薄くしています。
[センサースクリプト]
//センサーイベントを設定
Var EvtSensor
SetEventSensor MtdSenseTrain EvtSensor

//このセンサーが担当するポイント
VarPoint ObjPoint
get ObjPoint {ポイント名}

//編成検知時に実行されるメソッド
BeginFunc MtdSenseTrain
  VarTrain TmpTrain
  Var TmpType
//検知した編成オブジェクトを取得
  GetSenseTrain TmpTrain
//変数TmpTypeに検知した編成のVarTypeの値を取得
  mov TmpType TmpTrain.VarType

//[d']ポイントのグローバル変数にTmpTypeの値を代入
  mov ObjPoint.VarTrainType TmpType
//[e]ポイントの編成判別メソッドを実行
  call ObjPoint MtdCheckType
EndFunc
第一の重要点は、冒頭のVarPoint命令によるポイントオブジェクト変数の宣言と、続くget命令による代入です。get命令の第2引数の{ポイント名}は、実際にはレイアウト上に配置されたポイントに付けた名称に置き換えます。

この部分は、このセンサーが「私は{ポイント名}を担当するセンサーである」と述べている部分になります。以降、スクリプト内では、目的のポイントに何かをするに際し、常にこのポイント変数ObjPointを使っています。これも前回同様に、後々の修正の手間(get命令の{ポイント名}だけを書き換えれば、制御対象のポイントを簡単に変更できる)を考えての措置です。さらに、もう1つ別のセンサーとポイントの組に同じような仕掛けを組み込む場合、このget命令に続く{ポイント名}以外の部分は、コピー&ペーストするだけで使えます。

続いてポイントスクリプトに取り掛かりましょう。順序が前後しますが、先に[g]からいきます。
[ポイントスクリプト]
//正位切替メソッド
BeginFunc MtdStraight
  SetPointBranch 0
EndFunc
//反位切替メソッド
BeginFunc MtdTurnout
  SetPointBranch 1
EndFunc
ポイントの状態は、三叉ポイントを除けば要するに正/反位の2つしかありません。使う/使わないは別にして、とりあえずレイアウト上のすべてのポイントに上記のメソッドを予め用意しておくことをお奨めします。こうしておけば、そこへ至る処理はともかく、call {ポイント名} MtdStraight を実行すれば正位に、call {ポイント名} MtdTurnout としてやれば反位にポイントが切り替わります。[g]はこれがすべてです。

その上で、残る[f]の部分ですが、これは試みに読者の宿題にして敢えてサンプルコードは示さないことにしましょう。以下、この部分でやらなければならないことを列挙しますと・・・

[f]-1 センサーから編成判別の値を受け取るためのグローバル変数を宣言する。
[f]-2 センサーから実行されるメソッドを作る。
[f]-3 グローバル変数をif命令で調べ、ある条件に当てはまる場合とそうでない場合(追越列車と退避列車に相当)を判別すること。
[f]-4 [f]-3の結果に応じてポイント切替メソッドを実行すること。

になります。なお、[f]-4に際し、この場合実行する[g]ポイント切替メソッドは自分自身(ポイントオブジェクト)の中にありますから、call命令は、call {ポイント名} {メソッド名}ではなく、call this {メソッド名}になる点に注意してください。わからないことがあれば、随時コメント欄にどうぞ。

以上で、編成側に用意したグローバル変数の値に応じて、分岐ポイントを切り替える仕掛けの解説を終わります。ちなみに、合流ポイント、特に駅出発直後のそれについては、出発信号との連動や保安機能の組み込みが関係してくるのでこの手法では解決できません。これは、後日の課題となります。

次回へ>>
0

2007/5/2  8:24

投稿者:ghost
気にしなくていいです。>先に言うべきでしたね・・・すみません

言葉を選んでいると伝わるモノも伝わらなくなるので、特に何らかのスキルの伝達を狙っているときは語感が強い言葉を使わざるを得ません。

万が一、ボクがこの企画に嫌気が差した場合は多分黙って止めますから、続けて書いている限りは、基本的に感情を害していることは一切ないとお考えいただいて結構です。

逆に、語気を強くお感じになった際は、その部分は、ボクの感情の発露ではなく、最も(VRMスクリプトを制する上で)重要なツボがそこにあるのだ、とお考えいただきたく。

2007/5/1  22:12

投稿者:ゆゆぽん☆
先に言うべきでしたね・・・すみません。
信号編でも色々あるかもしれませんが、
よろしくお願いします。

2007/5/1  21:04

投稿者:ghost
祝着至極。
でも・・・

> 編成のスクリプトには、ポータブル編成
> スクリプトやその他のWizardをつかった
> スクリプトが書かれていて

それ、先に言おう...orz

メソッドの外、いわゆる“宣言部”と呼ばれる部分は、各オブジェクトのスクリプト先頭から「最初のBeginFuncまで」が実行されます。ご注意あれかし。

ちなみに、ご理解いただけているとは思いますが、100や250には特に意味はありませんので、ゆゆぽん☆殿の使いやすい数値に改めて使ってください。

明日から信号編が始まります。

2007/5/1  20:24

投稿者:ゆゆぽん☆
動きました!
編成スクリプトの
Var VarType
set VarType 100(あるいは250)
の記入場所が悪かったのかもしれません。
編成のスクリプトには、ポータブル編成
スクリプトやその他のWizardをつかった
スクリプトが書かれていて、その最後に
記入していたのを1番上にやったら解決しました。
Var宣言は最初でないといけないんですね・・・。
あと、センサースクリプトに
DrawVar TmpType を追加したら、
int 0だったのが、100と250、それぞれ表示され
ポイントも動きました。ありがとうございました。



2007/5/1  10:16

投稿者:ghost
構文的には間違いはないです。また、今、ボクのVRM環境でゆゆぽん☆殿の示したコードを組み込んでみたら意図通りに動作しました。

となると、怪しいのはセンサーの配置、ポイントの名前です。

(1) センサースクリプトの mov TmpType TmpTrain.VarType の直後に DrawVar TmpType を追加してみましょう。

センサーが編成を検知していれば、ログウィンドウにTmpTypeの値、すなわち検知した編成のVarTypeの値が表示されるはずです。

何も表示されないとすると、センサーにレールと異なる高さが設定されてしまっていて、編成が検知できていない可能性があります。

(2) ポイントの名称を再確認してみましょう。ゆゆぽん☆殿のコードでは“West”と名づけられたポイントをセンサーが制御することになっていますが、実はテストで走行しているポイントが“East”だった、というオチも、ないとは思いますが可能性としてはありえます。

また、レイアウト上に“West”と名づけられたポイントが複数ある場合も考えられます。同名のオブジェクトが複数ある場合、VRMはその名前で最初に見つかった部品に対してのみ制御をおこなおうとします。そのせいで制御が空振りしている可能性があります。


パッと思いつく可能性はこんなところです。

コメントのやり取りでは「部分」しか見えないので、最悪、メールにレイアウトを添付して送ってください。

2007/5/1  8:37

投稿者:ゆゆぽん☆
やはりおかしいです。
[ポイントスクリプト]
//Var命令で宣言
Var TmpType
Var VarTrainType
set TmpType 250

BeginFunc MtdCheckType

ifeq VarTrainType 250
call this MtdTurnout
else
call this MtdStraight
endif

EndFunc

だと、分岐すらしてくれません。
[編成スクリプト]
Var VarType
set VarType 100(あるいは250)
を記入してグローバル変数宣言はしているのですが・・。

>ボクをVRMビュワー代わりに使うな、ということです
言葉不足だったようで誤解を与えてしまいました。あのスクリプトでビュワーを起動すると、問題なく
立ち上がりますが構文が無視されてしまいます。
この文法は間違いなのでしょうか?
という意味だったのですが、誤解を与えてしまいました。すみませんでした。

2007/4/30  18:35

投稿者:ghost
多分それで動作します。
が、おそらく誤解されている部分があると思うので補足します。

> ifeq TmpType VarTrainType

は、素直に書けば ifeq VarTrainType 250 です。これは「もし、VarTrainTypeの値が250に等しければ」の意です。

ゆゆぽん☆殿の書き方を同様に読み下すと「もし、TmpTypeの値がVarTrainTypeに等しければ」になります。これをゆゆぽん☆殿が意識的にそうされたのであれば特段申し上げることはありませんが、もし、上に読み下したようなことを意識しておられないか、あるいは他のことを考えておられた場合は、今後のために注意が必要です。

また、変数名TmpTypeは、ここまでの流れで「センサー部品におうて、検知した編成のグローバル変数の値を一時的に取得しておくローカル変数」として使われたものです。

動作上は実害ありませんが、異なる用途に対しては異なる変数名を割り当てることをお奨めします。そうしないと、後で読み返したときに、どの変数が何を意味しているのか著しくわかりにくくなります。

それから、今回のように「動作はするけれども後日の災いの元になると思われる記述」については指摘しますけれども、基本的にはVRMスクリプトは多少まずい書き方をしていようが、意図通りの動作をすればそれでOKと見做して良いと思います(他の人に教授する場合を除く)。

何が言いたいかというと、ボクをVRMビュワー代わりに使うな、ということです。

VRMビュワーは、文法/名前解決がまずければ起動時エラーで、論理がまずければ意図せぬ動作をすることで、あなたの書いたスクリプトが正しくないことを教えてくれます。まずは、それを試みましょう。自分で動作を試みていないコードについて「こんな感じでしょうか?」と尋ねられるのは、ボクとしては望むところではありません。

2007/4/30  18:18

投稿者:ゆゆぽん☆
こんな感じでしょうか?

//Var命令で宣言
Var TmpType
Var VarTrainType
set TmpType 250

BeginFunc MtdCheckType

ifeq TmpType VarTrainType
call this MtdTurnout
else
call this MtdStraight
endif

EndFunc

2007/4/30  14:36

投稿者:ghost
if命令の使い方はそれで正しいです。

最初に示されたコードをそのままお使いなのだとすると、ここで評価されている変数TmpTypeに目的の値(編成オブジェクトでsetした値)が運べていないのが意図通りに動かない原因です。

> //[d']ポイントのグローバル変数にTmpTypeの値を代入
> mov ObjPoint.VarTrainType TmpType

は、変数ObjPointが指すポイントに所属する変数VarTrainTypeに、自分自身(ここではセンサー)に所属する変数TmpTypeの値を代入せよ、の意になります。

したがって、ポイント側にこれを受け取る変数VarTrainTypeがないといけません(Var命令で宣言する)し、if命令で比較する変数はこれでないといけません。

多分、これで意図通り動作すると思いますよ。

2007/4/30  11:48

投稿者:ゆゆぽん☆
説明不足でした。

ifeq TmpType 250
call this MtdTurnout
else
call this MtdStraight
endif
EndFunc

で、
TmpTypeと250が等しい時、
ここにあるMtdTurnoutを実行する
それ以外は
ここにあるMtdStraightを実行する

と思ったのですが・・・外れたようです。
if文は、
もし〜ならば、○○を実行する。
と思っているのですが間違いなのでしょうか?


コメントを書く

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




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