信号シミュレーションのアルゴリズム


今回のプログラムで重要なのは、やはり車(エージェント)の動き方です。

どのような状況で、どのような動き方をするのか、そのルールについてをメインに解説したいと思います。

と、その解説の前に、事前知識として「フレームレート」についての説明をしておきます。

1.フレームレート


パラパラ漫画やアニメは、1秒間に何枚のもの絵を表示することで、動いているように見えますよね。

動画もこれと同じで、1秒間に何枚もの画像(フレーム)を表示しています。

「フレームレート」とは、この単位時間あたりに処理するフレーム数のことです。

単位は、1秒当たりのフレーム数(frame per second:fps)がよく使われます。

この値が大きいほど滑らかな映像になり、この値が小さいほど雑な映像になります。

 

今回のシミュレーションやゲーム等では、このフレームレートの仕組みを使っています。

1秒間にいくつものフレームを処理することで、車やモンスターが動いているように見せているのです。

ただ、動画等のfpsとは逆で、何秒ごとに1フレームを処理するか(1フレームあたりの秒数)を考えます。

Javaでは、一定時間ごとに処理を呼び出す仕組みとして、Timerクラスというものが用意されています(詳細は検索してください)。

例えば今回のシミュレーションでは、100ミリ秒=0.1秒に1フレームを呼び出すようにしています(→ 1 ÷ 0.1 = 10fps)。

 

以下で解説する車の動き等では、このフレームレートの考え方が重要となります。

2.進行状態


進行状態とは、どのような状況にどれくらい車が進めるかを表すものです。

今回のプログラムでは、「aheadFlg」という変数で、「goNextStep」メソッド内で定義されています。

また、速度は1フレームあたり1マス移動と2マス移動の2段階にしています。

ルールは以下の通り。

  • 前方の空きマスが0~1マス・・・進行不可
  • 前方の空きマスが2~4マス・・・1マス進行可
  • 前方の空きマスが5マス以上・・・2マス進行可

空きマスというのは、車やストッパー(後で説明)が無い空のマスのことです。

 

なお、これはどれだけ進めるかを示すだけであり、実際に移動する距離とは異なります。

進行状態と実際の移動を同じにしていないのは、急発進や急加速をさせないためです。詳細は、次の項目で解説します。


3.実際の移動処理


↑現在の状態、進行状態、実際の移動の関係を示した表です。

現在の状態は、停止(0マス)、低速(1マス移動中)、高速(2マス移動中)となります。進行状態は前項のものです。

実際の移動処理についても、「goNextStep」メソッドで行っています。 

 

本来、停止状態から1マス進行可となった場合、低速状態に移ると考えるのが普通です。

しかし、前の車が発車した瞬間に、自分の車も発車することはありえないですよね。人間の反応速度を考えると、少したってから発車するのが自然です。

同じように、車の速度を上げる場合も、前の車が速くなった瞬間に自分の車の速度を上げることは不可能です。

 

そこで、停止状態→1マス or 2マス進行可(発進)、低速状態→2マス進行可(速度上昇)となった時、急に状態を変えるのではなく、数フレームたってから状態を変えるようにしています。

デフォルトでは、発進は2フレーム後、速度上昇は4フレーム後に行うようにしています。

実際のプログラムでは、nフレーム後までなら(1 ÷ n)という形で表し、
発進:startUp(1 ÷ 2 = 0.5)、速度上昇:speedUp(1 ÷ 4 = 0.25)で定義しています。

 

なお、上の状態から下の状態になった場合は、瞬時に下の状態に切り替えます。

高速状態→1マス進行可なら低速状態、低速状態→進行不可なら停止状態へすぐ切り替え。

高速状態→進行不可もすぐ停止状態になりますから、急ブレーキです。物理的にはおかしいのですが、シミュレーション内で衝突事故を起こさないために仕方がないと思ってください。なお、信号が赤になった瞬間くらいしか急ブレーキはおきません。

4.交差点での停止と右左折


交差点では、見えない障害物を置くことで、停止や発進を再現しています。

 

まず、図Aを見てください。

シミュレーションで車が通るマス(薄緑色の部分)には、マスの状態が記録されています。

この記録を基に、各車は前方の空きマスを計算しているのです。

何もない空きマスには「0」が入っています(図には書いてないですが、薄緑色の部分に「0」が入っています)。

車のマスには「1」が入っています。「1」のマスは空きマスではないので、車は減速して止まり、前の車に衝突しません。

 

信号が赤の時には、交差点の手前にストッパーを用意して「2」を入れます(濃い灰色のマス)。

実際のストッパーには色を付けていないので、車が自動的に止まっているように見えるのです。

 

 

右左折時も、この見えない障害物を利用して、車が交差点手前で減速するようにしています。

そのためのストッパーが、交差点中央の「-1」のマスです(薄い灰色のマス)。

このマスがあるため、右左折車は交差点手前で減速し、交差点に入ったあたりで停止するのです。

なお、直進車は関係がないため、「-1」のマスは「0」のマスと同じものとして扱います。

 

その後の左折車については、図Bを見てください。

左折車は①の位置にきた後、フレーム単位で①→②と移動します。ここだけは座標を基に移動を無理やり行っています。

そして、②になった瞬間、移動方向を左折方向に切り替えるため、③へと進めるのです。

 

その後の右折車については、図Cを見てください。

右折車は①の位置にきた後、フレーム単位で①→②→③→④と移動していきます。ここも左折車同様無理やりです。

そして、④になった瞬間、移動方向を右折方向に切り替えるため、⑤へと進めるのです。

なお、右折の場合は、右折可能と判断できる以下の場合のみするようにしています。

  • 対向車がいない時・・・具体的には、交差点内部から23マス分(図Cの薄黄色の部分)に対向車がいない時。
  • 対向車も右折の時・・・現実ではできない場合も多いが、シミュレーションでは必ずできることにしている。
  • 赤信号になった時・・・現実でもよくあるやつ。これをしないと交差点に取り残される。

実際の状況は、You-Tubeの動画で見てもらえると分かりやすいと思います。

なお、右折時に③の車位置と右左折用のストッパーが被っていますが、マスの状態は毎フレーム更新されるので、問題ありません。
次のフレームではストッパーに戻ります。

 

 

また、今回のプログラムでは、ストッパーについては「AnimationPane」クラス内の「paintComponent」メソッドで、右左折の移動については「goNextStep」メソッドで処理しています。

図A

図B

図C