Parallel Musical Chairs

動機

「グリッド上にランダムに置かれたものがバラバラと動き続ける」ような動きは演出として想起されやすい一方で、いざ組もうとすると少しトリッキーであることに気付いた。自分の周囲を見渡し、空いたマスへと移動していく動作はいかにも個体毎の処理に思えるものの、移動先が被らないよう統制をとるには全体を俯瞰した視点が必要になる。本来なら頭のコマからひとつずつ移動先を決めていくような処理がシンプルそうだが、効率化 (およびロマン) のためにこれを並列処理のまま実現するアプローチをいくつか考えてみる。さらに移動に際し、いくつかの諸条件を加え調整することで、全体としてどのような印象操作が可能になるかを検証する。

※ 実際に椅子が足りなくなる状況はないのだけれど、移動しつつ互いに場所の確保できるかせめぎ合う緊張感が想像しやすいという意味で、並列椅子取りゲーム(=Parallel Musical Chairs)と呼んでみた

共通前提

  • 置かれるグリッドの方をマップ、そこに置かれた動くものをエージェントと呼ぶ。
  • マップにはエージェントが置かれたONセルと、不在のOFFセルがある。
  • 処理はマップ側のデータに対して行う。(エージェントはあとからマップに追従)

アルゴリズム

🗳️ TouchDesigner サンプルファイル (toe - 2025.32460)

1 Staggered (1 step)

  1. ONセルについて、互いに被らないよう順々に決められた方向に沿って移動する
  • 四角グリッドであれば 右、左、上、下、右… など
  • 全体の処理毎に、1つ分ずつ方向をずらしていく

備考

  • ⭕ 1ステップの処理でシンプル
  • ❌ 方向決定がマップのトポロジーに依存するため、マップ形状によっては使えない
  • ❌ ランダムさがつけづらく、動きのパターンが露呈しやすい

2 Match (2 step)

  1. 全セルについて、自分とはON/OFFが異なる状態のセルを1つ目標にする
  2. 目標のセルの目標が自分自身だった場合に移動する

備考

  • ⭕ ONセルにもOFFセルにも共通の処理でOK
  • ⭕ 並列処理にあたって、自分のセルの更新のみで完結する (他セルの更新が不要)
  • ❌ 移動できそうな状況にあっても、双方からのマッチが必要になるため、不発のケースがやや多い

※ このチュートリアルで最初に知る
Entagma - Vladyslav Lavrenov: Building A Path Solver

3 Round-Robin (2 step)

  1. ONセルについて、周囲のOFFセルから目標を1つ選ぶ
  2. OFFセルについて、周囲のONセルの目標を総当りして自分自身であれば移動

備考

  • ⭕ ほぼ 総当り✕総当り なので、不発が大幅に減る (step1で選ばれないケースはある)
  • ❌ 条件分岐が少し増えるので、実装方法によっては複雑になる

追加条件 (フィルタリング)

各セルの移動目標を決めるにあたり、以下のような条件を加えることで 全体としての振る舞いを調整している。

  • (目標のセルが埋まっていないかどうか : 最低条件)
  • Sleep Time: 前回の移動から設定したスリープ時間が経過しているか (Minimum + Random)
  • Probability: 移動確率を満たしているか
  • Avoid Prev Cell: 直前にいたセルを避けるかどうか

これに加えて、処理全体に対する

  • Frame Interval: 前回の入れ替えからの発動フレーム間隔

を設けている。例えば同じような移動頻度を作るにしても、どのパラメータを軸に調整するかによって、全体の印象を変えることができる。(以下で比較)


挙動比較

アルゴリズム間の違い

パラメーターを揃えて行った3タイプの比較。
用途にはよるものの、3つともパラメータを調整していくことで大体似た感じで動いてしまうため、 ここでは特に違いの顕著な例を出してみた。

強いて特徴を挙げると

  • Staggeredは少し同じ場所での行き来や一定区画でのパターン化が多く、全体のシルエットが崩れにくい
  • Matchは良い感じに見えるが、Round-Robinに比べるとミスマッチが多くなり、同じ確率でも移動量が少ない (ムラがある)

パラメータ調整による違い

パラメータを変えつつ、同程度の移動頻度になるように設定した。

Mechanical

Frame Intervalを上げると全体にリズム感や規律っぽさが生まれる。
さらに Sleep Timeのランダム比率を下げてより個々の挙動差を減らしてみた。
時間あたりの移動頻度が減る分をProbabilityを上げて相殺している。

Organic

Frame Intervalを1にすることで全フレームで入れ替え計算を行いつつ、Probabilityをぐっと落とし、Sleep Timeのランダム比も上げた状態。 全体として有機的な印象になる。パターンの見えがちなStaggeredでもこの調整でかなり見えづらくなる。


適用例

  • 同じ仕組みをベースに、マップ形状や移動を工夫してみる。
  • 基本的には各エージェントの移動決定の瞬間の時間を記録しておき、
    (移動開始時刻 - 現在時刻) / 移動時間(スピード)
    から正規化された補間率を得る。
  • その0〜1を回転に紐づける、さらに数段階に分ける、二次動作に紐づける…
    など加工してこねくり回す。

01

  • 上記作例をテキストで置き換えたもの
  • 移動速度に応じて2Dテクスチャ配列をオフセットしている
  • ギリギリまで隙を作らないようにした状態
  • 空きにすぐ次が入るので、列としてうねりが移動していくような見た目になる

02

  • 移動を回転に置き換えたもの
  • 回転結果を累積しつつ、次の移動の初期値として用いる

03

  • マップに三角グリッド + 移動に極座標を用いたもの
  • ピンの揺れは、各点を外周方向に離して複製したものにバネ拘束をかけ、それを各々の目標点として使うことで擬似的に表現した
  • 移動を2段階に分けて、前半を次の移動方向へ向くことへ充てた

04

  • 伸びていく線の先端として使ったもの
  • 程よく交差を回避するような振る舞いになる