お盆明け、コミケ明けに国際鉄道模型コンベンション21thがありました。
私は初参加でしたが、山手線ゲーム2ndのプログラムを少しだけ関わりました。改めまして、遊んでいただいた方ありがとうございました。
少しだけ関わったのと技術情報開示のある程度の許可を頂いたので、忘れないうちに関わった部分の反省及び仕組みを少しだけ公開いたします。
目次
今回関わった部分と設計思想
昨日までの3日間、たくさんのお客さまにご来場いただきました。ありがとうございました。
毎回恒例「何かの会社ですか?」という質問もいただきました。RFCは社会人サークルですので、本日からはスタッフも全員社会復帰。#山手線ゲーム2nd#国際鉄道模型コンベンション pic.twitter.com/SMUVrm1O56
— RFC@ダイヤ運転フェスタ9/24,25 (@RFC_PR) August 21, 2022
この画面に出ているところを担当いたしました。
お客様に見える部分で、車掌スイッチを扱うとドア開閉するし、発車メロディーを扱うと発車メロディーが鳴ったり止まったりします。
まずこの画面ですが、神に書いて頂いたのですが、1枚絵ではなくて1つ1つのパーツがバラバラになっています。
透過画像なので下から順番に重ねていけば綺麗に並びます。
レピーター、ATOS等もベースはこれで、ATOSのLED表示はそれを組み合わせて自由に表示できるような仕組みです。
ドア開閉部分は動画です。
当初はGIFで行く予定でしたが、工数見合いで動画を全パターン出してもらってそれを組み込むことにしました。
列停やレピーター、ATOSはGIFを再生しているわけではなくて組み合わせて表現しておりました。
絵の部分の設計思想はお任せしていたので私が考えたわけではありませんが、後述に必要な説明なのでちょっと序章として書かせていただきました。
で、ここからほんの少しだけ技術的な話になります。
意外と簡単そうに見えるのですが、何だかんだで考えることが多いのが今回のプログラムです。
電車が来たら電車を表示して、ドア開けたらドアを開けて、発車メロディーを鳴らしたら発車メロディーを鳴らせばいい。言ってしまえばただそれだけですが、これらの処理を内回り外回りで同時に到着や発車メロディーが鳴っても大丈夫なように、かつプログラムのメンテナンス性を意識しながら書いていく必要があります。
お金が発生する仕事ではないので技術者として色々試そうとし、今回のこのプログラムは正直に言うと大失敗なのですが、とにかくコードの量を減らすということを目標としました。
お金が発生しないかつ、人様の目に触れるようなプログラムを書くことなど滅多にない機会です。一つの挑戦、お試しとして今回は駅の状態をビットで判断するということをしました。
状態を考えてみよう
初期状態は列車がいないものとして扱います。
状態①接近
列車が接近したとき、ATOSに「電車が」「来ます」と表示します。
同時に、接近放送を鳴らします。
ATOS制御はsetInterval()で、繰り返します。
処理は
if (direction == 1) {
//外回り
if ($('#soto-densyaga').css('display') == 'block') {
// 表示されている場合の処理
$('#soto-densyaga').hide();
$('#soto-kimasu').show();
} else {
// 非表示の場合の処理
$('#soto-densyaga').show();
$('#soto-kimasu').hide();
}
}
一定間隔で無限にループさせて、「電車が」が表示されているときは、「電車が」を消して「きます」を表示。
「電車が」が非表示のときは「電車が」を表示。
初期状態は「電車が」が非表示なので「電車が」を表示。以降ループでいい感じに電車がきますを交互に表示することができました。
この時に、状態②で表示させる列車がE231かE235かを判別するためサーバーから情報を受け取ります。
なお、タグの調子が悪いとか何らかの理由で受信できなかった場合はE231と判定するようにしました。
状態②駅に到着
ドアは自動では開きません。
車両がホームトラックに突っ込んだら、画面に列車を表示させる必要があります。
状態①で取得した車両情報を参照しながら車両を駅に表示させます。
状態③駅を出発
車両がホームの次のトラックに突っ込んだら、画面から列車を消す必要があります。
また、ATOS状態、レピーターを全てリセットする必要があります。
ATOSが「延発」を指示しているときは、そのままATOSが表示されたまま出発することになりますので、この処理を怠ると永遠に延発が残り続けるバグが残ってしまいます。
割り込み処理① ATOS(延発/出発/通知)
これらはどこで来るかわかりません。適当なタイミングでどこでも来ます。
ATOS表示や列停の表示は、状態①のようなsetInterval()を駆使して再現します。
割り込み処理② レピーター/列停/ドア開閉/発車メロディーON/OFF
どちらかと言うとユーザー入力系の操作です。
割り込み処理①と同様にいつ来るかわからない処理ではありますが、どちらかと言うと入力される系、駅の状態を表すのでATOSと分けて考えます。
ビットの考え方
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
駅情報 | 到着 | 接近 | レピーター点灯 | ドア開 | 発車メロディー再生 | 発車メロディー停止 | 列停 | |
ATOS | 抑止 | 通知 | 延発 | 出発 | 接近 | 試験 |
内回りと外回りでこれらの状態を組み合わせで持つので、駅と状態はたった4つの変数で定義することができます。
たとえば、駅情報が0b00100000のときは接近。0b00110000のときは接近中でレピーター点灯、のような形で状態を表すことができます。
リセットしたければ0b00000000にすれば良いです。
ATOSも横に足せばさらに変数を減らすことができますが、流石に変数が長くなりすぎますし、8bit、オール1で255という気持ちよさが無くなるのでやめました。
ですが、これは正直失敗だったかなと思います。書き方にもよりますが、結構後で修正しようとしたときに可読性があまりないのが災いして非常にデバッグがしにくいです。
一番簡単な方法は、すべてに対して変数を持つことですが、それはそれで定義が大変ですし行数も長くなりますしそれはそれで可読性はあまり良くないので、
次があれば連想配列で作るのがいいのかなと思っています。
実はこんなものも作ってました
外回り内回りで作ったのに進行方向がめちゃくちゃだったり、そもそも線形が鏡になっていたり
ほぼ完成したと思った途端、このような大幅ミスに気がつき結局ボツとなった内部向けTIDを作成していました。睡眠って大事です。
寝てはいたものの、睡眠時間は不足気味だったという言い訳をします。
次があれば強化して、チラ見えしたときになんか本物の駅員みたい!ってなるようなものを作成しようと思います。
下にあるボタンたちは、完成していて色々なイベントを起こせるようになっていました。
抑止も起こせますし、延発、通知、列停、出発指示は完璧。
実際に在線したときは赤で表示され列番も表示できる予定でした。
鎖錠は出ませんでしたが、ここまで完璧にできたらいいなぁと思ったり。関係者が持っているとカッコいいシリーズでした。
おわりに
今回遊んでいただいた方には感謝しかありません。
更に、楽しかったというお言葉はやってよかったと達成感がありましたし、嬉しかったです。