Tips: 文字列変数を活用して架線ストラクチャのRepeater構文化困難な部分を効率的にこなす

Tips: 文字列変数を活用して架線ストラクチャのRepeater構文化困難な部分を効率的にこなす

1.課題

架線柱が等間隔で設置されている区間、あるいは等間隔でなくても演出上問題ないため等間隔として扱う場合ではRepeater構文で制作の手数が大幅に圧縮できますが、駅・カーブ・分岐器が絡む部分などでRepeater構文を採らない判断をした場合は構文の量手を動かしてキーボードで入力する量が線路の数に比例して増大し、Repeater構文採用区間より作業量が10倍以上にふくらむことがあります。

例:

ある複雑な箇所のスクショ

マップ入力例

$MLS-38465;//架線柱
Structure['Pole_m09_04'].Put('down', 0,0,0, 0,0,0, 1,0);
Structure['Pole_m09_04_2'].Put('uji_up', 0,0,1.8, 0,0,0, 1,0);
Structure['Ocl_s_27m_B'].Put('down', 0,0,0, 0,0,0, 1,27);
Structure['Ocl_s_27m_B'].Put('up', 0,0,0, 0,0,0, 1,27);
Structure['Ocl_s_30m_B'].Put('4', 0,0,0, 0,0,0, 1,30);
Structure['Ocl_s_30m_B'].Put('uji_down', 0,0,0, 0,0,0, 1,30);
Structure['Ocl_s_30m_B'].Put('uji_up', 0,0,0, 0,0,0, 1,30);
$MLS-38438;//架線柱
Structure['Pole_m09_05'].Put('down', 0,0,0, 0,0,0, 1,0);
Structure['Ocl_s_25m_A'].Put('down', 0,0,0, 0,0,0, 1,25);
Structure['Ocl_s_25m_A'].Put('up', 0,0,0, 0,0,0, 1,25);
Structure['Ocl_s_25m_A'].Put('4', 0,0,0, 0,0,0, 1,25);
Structure['Ocl_s_25m_A'].Put('uji_down', 0,0,0, 0,0,0, 1,25);
Structure['Ocl_s_25m_A'].Put('uji_up', 0,0,0, 0,0,0, 1,25);
$MLS-38413;//架線柱
Structure['Pole_m09_06'].Put('down', 0,0,0, 0,0,0, 1,0);
Structure['Ocl_s_35m_B'].Put('down', 0,0,0, 0,0,0, 1,35);
Structure['Ocl_s_35m_B'].Put('up', 0,0,0, 0,0,0, 1,35);
$MLS-38378;//架線柱
Structure['Pole_m09_07'].Put('down', 0,0,0, 0,0,0, 1,0);
Structure['Ocl_s_40m_A'].Put('down', 0,0,0, 0,0,0, 1,40);
Structure['Ocl_s_40m_A'].Put('up', 0,0,0, 0,0,0, 1,40);

架線ストラクチャは、長さと偏移ごとに作ります。偏移は右から左の場合「A」その逆は「B」偏移なしの場合「C」とします。ストラクチャリストは以下のようになっています。

# 架線
Ocl_s_12m_A,Structure2025/Ocl/Ocl_s_12m_A.x
Ocl_s_12m_B,Structure2025/Ocl/Ocl_s_12m_B.x
Ocl_s_15m_A,Structure2025/Ocl/Ocl_s_15m_A.x
Ocl_s_15m_B,Structure2025/Ocl/Ocl_s_15m_B.x
Ocl_s_20m_A,Structure2025/Ocl/Ocl_s_20m_A.x
Ocl_s_20m_B,Structure2025/Ocl/Ocl_s_20m_B.x
(中略)
Ocl_s_63m_A,Structure2025/Ocl/Ocl_s_63m_A.x
Ocl_s_63m_B,Structure2025/Ocl/Ocl_s_63m_B.x
Ocl_s_65m_A,Structure2025/Ocl/Ocl_s_65m_A.x
Ocl_s_65m_B,Structure2025/Ocl/Ocl_s_65m_B.x
Ocl_s_75m_A,Structure2025/Ocl/Ocl_s_75m_A.x
Ocl_s_75m_B,Structure2025/Ocl/Ocl_s_75m_B.x

# 架線柱
(略)

# 架線支持具
(略)

架線1か所ごとに線路の数だけ偏移と長さを書き換えながらStructure.Putするのは非常に大変です。

軽く見積もると10kmあたりで構文600回打ち、長さと偏移の書き換えやカーソル移動でのキーボード入力は約10000回にのぼります。こんなのミスの温床以外の何物でもないですね。

2.ポイント

  • 架線の長さが頻繁に変わるためRepeaterで書けない → しゃーない
  • 1000回以上のStructure.Putでストラクチャ名(長さ)と偏移ケース以外はほぼ共通 → 文字列変数の活用で作業量圧縮(今回の本題)

3.実践例

やることはstructureKeyに固定文字列と演算子と文字列変数使えることを知るだけです。

ある複雑な箇所のスクショ

マップ入力例

$MLS-33793;
//架線柱
Structure['Pole_2_101_2015_41'].Put('down', 0,0,0, 0,0,0, 1,0);
$NextPoleDist = 23;
$NextPolePos = 'A';
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('down', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('up', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('down_sub', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('up_sub', 0,0,0, 0,0,0, 1,$NextPoleDist);
$MLS-33770;
//架線柱
Structure['Pole_2_101_2015_41'].Put('down', 0,0,0, 0,0,0, 1,0);
$NextPoleDist = 27;
$NextPolePos = 'B';
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('down', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('up', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('down_sub', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('up_sub', 0,0,0, 0,0,0, 1,$NextPoleDist);
$MLS-33743;
//架線柱
Structure['Pole_2_101_2015_41'].Put('down', 0,0,0, 0,0,0, 1,0);
$NextPoleDist = 33;
$NextPolePos = 'A';
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('down', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('up', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('down_sub', 0,0,0, 0,0,0, 1,$NextPoleDist);
Structure['Ocl_s_' + $NextPoleDist + 'm_'+ $NextPolePos].Put('up_sub', 0,0,0, 0,0,0, 1,$NextPoleDist);

$NextPoleDist = 33;のように架線長さ(m)を入れ、$NextPolePos = ‘A’;のように偏移を入れると、ストラクチャ名「’Ocl_s_’ + $NextPoleDist + ‘m_’+ $NextPolePos」は「’Ocl_s_33m_A’」として読み込まれます。Structure.Putのspanにも$NextPoleDistを活用することで手入力回数をさらに減らしています。

こうすると架線配置は$NextPoleDistと$NextPolePosを管理するだけの作業となり、改善前より圧倒的に楽になります。書き方に慣れたら作業量としてはRepeaterの管理より微妙に多い程度に収まります。この楽々化は文字列変数を活用した効果によるものです。

今回は架線でやってみましたが、類似する部品ストラクチャをいっぱい配置してきめ細やかな演出をする別の作業(例えば分岐器など)でも同じ手法で効率改善できそうです。まあ、偏移ABABAB…みたいなパターンをRepeater構文のstructureKey1, structureKey2, … , structureKeyNでまとめられるのならそっちの方が先にやることになりますが。

注意点としては、キロ程ごとに変数がコロコロ書き換わるので、作業に関係しないところを巻き込まないように変数の命名は衝突リスクを小さくするために他の作業でまず使わないだろう名前にすることです。それと、久しぶりに進める場合に自分が思い出す用または自分のシナリオを活用して他の方が拡張シナリオを作られる場合に作業しやすいよう簡易マニュアルをヘッダー付近にコメントで入れておくと便利でしょうね。

4.まとめ

  • 架線配置に文字列変数を活用して作業効率を10倍くらい上げた
  • structureKeyに固定文字列と演算子と文字列変数使えることを知るだけでマップ制作負担は劇的に減る
  • RepeaterでまとめられるのならRepeaterの方がベター

5.参考リソース

公式ドキュメント(https://bvets.net/jp/edit/formats/route/map.html)うち今回関連する箇所を以下に引用するので読むときの補助になれば幸いです。

変数

変数

数値や文字列を変数に記憶させることができます。変数に値を代入するには、変数、等号 ( = )、値またはの順に記述します。

$foo = 1.067;
$bar = ‘Hello’;

引数やキーに変数を記述すると、変数に代入された値が参照されます。

Track[$bar].Gauge($foo); # Track[‘Hello’].Gauge(1.067) と書いたことと同じです。
$foo2 = $foo; # $foo2 に 1.067 が代入されます。

変数に代入できるのは、数値、文字列のいずれかです。文字列はクォーテーション ( ‘ ) でくくります。変数名の先頭には $ を付けます。変数名に使用できる文字は、英字 (A~Z、a~z)、数字 (0~9)、アンダースコアー ( _ ) です。

演算子

演算子

変数への代入、引数キーに演算子が使用できます。

$foo = 1 + 2; # $foo = 3 と等価です。
Curve.Gauge(1067 / 1000); # Curve.Gauge(1.067) と等価です。

以下の演算子が使用できます。インクリメント、デクリメント、二項代入演算子には対応していません。

演算子意味
+加算または文字列結合
減算
*乗算
/除算
%余り

+ は、被演算子が数値の場合には加算、被演算子が文字列の場合には文字列結合を表します。被演算子が数値と文字列の組み合わせの場合、数値を文字列に変換した後、文字列結合を行います。

$bar = ‘Hello’ + ‘World’; # $bar = ‘HelloWorld’ と等価です。
Track[$bar + 10].Gauge(1.067); # Track[‘HelloWorld10’].Gauge(1.067) と等価です。
$bar = 1 + 2 + ‘3’ # $bar = ’33’ と等価です。

演算子の優先順位は以下の通りです。

優先順位演算子
1括弧
2単項演算子
3* /
4+ –

ストラクチャー

Structure[structureKey].Put(trackKey, x, y, z, rx, ry, rz, tilt, span)

ストラクチャーを設置します。

structureKey: ストラクチャー名 (ストラクチャーリストファイルで定義した文字列)
trackKey: 配置先の軌道名 (0: 自軌道)
x: 軌道からの x 座標 [m]
y: 軌道からの y 座標 [m]
z現在の距離程からの z 座標 [m]
rx: 軌道に対する x 軸回りの角 [deg]
ry: 軌道に対する y 軸回りの角 [deg]
rz: 軌道に対する z 軸回りの角 [deg]
tilt: 傾斜オプション (0: 常に水平, 1: 勾配に連動, 2: カントに連動, 3: 勾配とカントに連動)
span: 曲線における弦の長さ [m]

連続ストラクチャー

Repeater[repeaterKey].Begin(trackKey, x, y, z, rx, ry, rz, tilt, span, interval, structureKey1, structureKey2, … , structureKeyN)

ストラクチャーの連続配置を現在の距離程から開始します。ストラクチャーは、軌道に沿って一定間隔に配置されます。

repeaterKey: 連続ストラクチャー名 (任意の文字列)
trackKey: 配置先の軌道名 (0: 自軌道)
x: 軌道からの x 座標 [m]
y: 軌道からの y 座標 [m]
z: 軌道からの z 座標 [m]
rx: 軌道に対する x 軸回りの角 [deg]
ry: 軌道に対する y 軸回りの角 [deg]
rz: 軌道に対する z 軸回りの角 [deg]
tilt: 傾斜オプション (0: 常に水平, 1: 勾配に連動, 2: カントに連動, 3: 勾配とカントに連動)
span: 曲線における弦の長さ [m]
interval: 配置間隔 [m]
structureKey1, … , structureKeyN: ストラクチャー名 (ストラクチャーリストファイルで定義した文字列)

interval の整数倍の距離程 (dist) にストラクチャーが配置されます。ストラクチャーを N 個記述した場合、(dist / interval) mod N + 1 番目に記述したストラクチャーが配置されます。

つまりRepeater.EndまでstructureKey1, structureKey2, … , structureKeyN,structureKey1, structureKey2, … , structureKeyN,structureKey1, structureKey2, … , structureKeyN, … という順序で連続配置されるということです