2006/6/28

編成の走行距離を算出するメソッド試作版  VRMスクリプト禅問答
45-50s氏のこのエントリを読んで、発作的に。
編成の先頭が音源切替用のセンサーを踏んだ瞬間に編成全体の走行音が変わるので、例えば地上カメラで眺めていると、列車の後部はまだ鉄橋を渡っているのに音はデフォルトに戻っていたりします。
もっともVRM4では車両ごとに音源を設定できますから、結構大変そうではありますが、工夫次第でこれは回避できます。

編成の先頭の台車が鉄橋(と言うか、いろんな音声切替の開始位置)を知らせるセンサーを踏んだ時点から走行距離を測り始め、1両分の長さを走るごとに、1両ずつ音声リソースを切り替えていくというのが、まず思い浮かぶ「工夫」のしどころ。
鉄橋の出口では同じコトを逆にやればいいし、途中で編成が反転(ボクも氏が言うように「わけわからん運転せずに、ちゃんと駅で方向転換をすればいい」とは思うけれども)した場合も、既に音声切替がおわったところからロジックを逆転して適用すればいい。

いずれにせよ、編成が自分自身が走った距離を測る方法が必要になる。これがないとこの方法は取れないし、また、他用途にも応用が広そうな気がする。で、試作してみた。


※ 以下のスクリプトはVRM4実環境で未検証の試作品です。有り体に言うと、ボクが忘れてしまわないようにメモしているだけです。実際に組み込んでみてエラーが出たらコメント欄で指摘してください、デバッグしますので。

[編成スクリプト]

//公開プロパティ
Var VarDistanceCounterTotal //総走行距離記録用(m)
Var VarDistanceCounterSub //区間走行距離記録用(m)
Var VarDistanceCounterDelta //単位時間走行距離(m)
Var VarSpeedPrevious //前回計測された走行速度(Km/h)

//イベント定義
Var EventDistanceCounter //イベント変数
SetEventTimer this MtdDistanceCounter EventDistanceCounter 100

//走行距離計測メソッド
BeginFunc MtdDistanceCounter
//
//0.1秒毎に走行距離を加算する
//
//ローカル変数宣言
Var TmpDistance //距離計算用(m)
Var TmpSpeed //走行速度取得用(Km/h)
//走行速度取得
GetCurrentSpeed TmpSpeed
//単位時間走行距離算出
mov TmpDistance TmpSpeed
add TmpDistance VarSpeedPrevious
div TmpDistance 72.0
mov VarDistanceCounterDelta TmpDistance
//走行距離加算
add VarDistanceCounterTotal TmpDistance
add VarDistanceCounterSub TmpDistance
//走行速度保存
mov VarSpeedPrevious TmpSpeed
EndFunc
このスクリプトを編成に組み込んでも、目に見えては何も起きません。ただ黙々と、0.1秒(100ミリ秒)毎に冒頭で宣言しているグローバル変数が更新され続ける、というだけのコードです。
やっていることは至極単純で、タイマーイベント内で0.1秒間に走った距離=(今の速度+0.1秒前の速度)×0.1秒÷2、を計算し続けているだけです。こうすることで、他の(つまり、実際になんらかの処理をおこなう)メソッドから、冒頭で宣言しているグローバル変数が参照できるようになります。

VarDistanceCounterTotal/Subの2つを用意しているのは、〜Totalは走行開始からの累積距離として置いておいて(何に使うかはともかく)〜Subは必要に応じて0に戻し、そこからの走行距離を調べるのに使いましょう、という作戦です。自動車の距離メーターと同じですね。

ちなみに、0.1秒毎というのは特に根拠はありません。適当です。結局のところこの計算は近似値を得ているに過ぎないので、計測間隔が大きくなれば大きくなるほど誤差が生じます。逆に計測間隔を小さくすればより正確な走行距離を得ることが出来ますが、当然短い時間に何度も同じメソッドが繰り返し実行されるますからビュワーが重くなります。また、あまりに間隔を狭めると、計算された距離がVRMスクリプトの小数の有効桁(小数以下第6位)を割ってしまって意味を失う場合もあり得ます。
60Km/hで走行する列車が0.1秒間に走る距離は、1.7mほどですから、まぁ、こんなものかな、と思って0.1秒にしてみました。ビュワーが重いと思う場合はSetEventTimerの最後のパラメータを増やしてください。たとえば500(0.5秒)に。このとき、単位時間走行距離を求める場合の数値が変わりますから、div命令(割り算)のパラメーター72.0を、100が500になった分、つまり5倍ですが、これに応じて5で割ってください。つまり、72.0を14.4にすればOK。その分だけ精度が下がりますが、実用上は問題ないと思います。

具体的な応用方法を、鉄橋の通過音のケースで例示してみることにしましょう。まず、編成が鉄橋に差し掛かったら(つまり、センサーを踏んだら)以下の処理を実行します。

(1) 1号車の走行音を鉄橋用に変更する。
(2) 変数VarDistanceCounterSubを0にする。
(3) 0.1秒毎にVatDistanceCounterSubが1号車の車両の長さに達したかを判定するタイマーイベントを設定する。

です。
ミソは(3)で、もちろん条件がみたされたら(つまり2号車が鉄橋にさしかかったら)、今度は2号車に対して同じことをすればOK。これを末尾の車両まで繰り返せば、鉄橋に乗っている車両のみに鉄橋用走行音を設定することが出来ます。鉄橋から普通の区間に戻る場合も同じ方法で対処できます。

編成の途中反転については、正直そこまで対応する必要もないとは思うのですが、(3)の都度、適切にカウントさえしておけば、SetEventHomeで方転を検知した時点で何両目までが鉄橋に入ったか(または出たか)は知ることができますから、あとは適当に変数で示される条件を事前に整えてさえやれば、普通に鉄橋を通過する場合と同様に(1)〜(3)を繰り返すことで処理できます。

ひょっとすると45-50s氏が想定しておられた解法はこれとは異なるかも知れませんし、もちろん、これが唯一最適解でもありませんが、なんか対欧州工作ばっかり書いているのもアレゲかな、と思うので書いてみました。
0

コメントを書く

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




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