Closed30

ゲーム向きな非チューリング完全なステートマシン記述言語の考察

eihigheihigh

背景

  • 経験上ゲームを構成するオブジェクトのほとんどは有限オートマトンである
  • プッシュダウンオートマトン以上の複雑さを有する処理はプログラマーが担保し、有限オートマトン程度の複雑さはプランナーが直接触ることで、複雑さに起因するバグを防ぎつつ開発速度も向上するという理想的なゲーム開発の分業を実現できるのではないかと考えた
  • あくまでイメージであって数学的に正確な表現ではないことに注意
  • RPGツクールでいうところの「イベント」とは完全に一致しないまでも概ね同じ方向を向いている
  • 一方、Unity をはじめとするゲームエンジンにはこの分業がうまくできていないという感覚を覚えている
  • 「ステートマシン」の表現手法として、しばしば「ステートを意味する丸や四角を、遷移を意味する矢印でつなぐ」という手法が用いられる(AWS Step Functions や Unity Animator)が、それとは逆に、「イベント列」を主役として記述するべきだろうと考える
    • 正規表現は、受け入れる文字=イベント列の羅列であり、とりうるステートは暗黙に決定されるのと同じ
eihigheihigh

以下は本当に雑多なメモ

  • 動画編集ソフトのキーフレームのように、時間変化を扱う機会が非常に多いのでうまく扱えるようにしたい
  • 見かけ上一つのオブジェクトでも、例えば拡大率と透明度はまったく別の変化をするなどがあると思うので、複数のの有限オートマトンが見かけ上一つのオブジェクトに作用できるようにしたい
eihigheihigh
  • ゲーム上のオブジェクトすべてをFSMで表現できるようにするのがおそらく望ましい(カメラやエフェクトまで)
  • FSMで記述されたオブジェクトが主体であって、プログラマーの領分に追い出したロジックを適宜利用するような形
eihigheihigh
  • 「そこはプログラマーが持ったほうがさすがによかろう」的な領域との接合面をどうするかが最大の難所
  • あくまでイメージだが、スタックが深いか集合が複雑ならプログラマーが持ったほうがいい気がする
eihigheihigh

それ以上にオブジェクト同士の相互作用をどうするかが課題であるな。
ツクールならイベントページという仕組みで変数などが変化したタイミングで遷移を行う。

eihigheihigh

結局のところ相互作用/状態の同期をどうすんねん、が一番難しくてプログラマーの領域になる。

メインループを前提とすると状態の同期は以下の2つのどちらかになる。

  • オブジェクトが何かの状態をこまめに観測する
  • 何かがオブジェクトに状態を書き込む

このへんを怠ると、メニュー画面でもお構いなしに動くオブジェクトがメニューバグを引き起こしたりするのだ。しかしメニュー画面の状態を考慮してオブジェクトを作るのは現実的ではないし開発速度を低下させる。ゲームの要件に合わせて厳密に考える必要があるので、プログラマーの仕事になる。

eihigheihigh

オブジェクトがてんでばらばらに動く(エフェクトが代表的な例)ならばプランナーやアーティストに任せてもよいが、オブジェクト同士で統率をとらねばならない場合(の全てかどうかは検討の余地あり)はプログラマーが担うとし、その両者をどう線引し、どう連携させるかが鍵になる。

eihigheihigh

まあこのへんは実際に相当難しい。

たとえば「坂を登る途中でセーブして復帰すると変な位置でスタートできる」を防ぐために当たり判定が解決し終わるまではセーブできないとかすると、今度は位置関係によって当たり判定が一生解決しないせいで一生セーブできなくなる問題が生まれる可能性があり、その対策としてタイムアウトを設け、タイムアウト後にセーブしたときは強制的に正しい位置に戻すとか、そういうのを考えるのはプログラマーの仕事。

eihigheihigh

相互作用の話に戻すがこれも同じことで、たとえばカメラ(明確に世界に一つしか存在し得ないもの)をオブジェクトが操作する場合、複数のオブジェクトが同時に操作しようとしてしまうとあり得ない位置にカメラが飛んでいったりする。

飛んでいかなくとも、同時に操作した別のオブジェクトにカメラ位置を上書きされて想定していないカメラ角度になったりする可能性もある。

カメラだけでなくBGMなどでも同様。

eihigheihigh

完全にプログラマーの領分な話題だが、この「同時発生するイベント」にどう向き合うか。メインループ前提なら、ループ内で起きた複数のイベントの前後関係は特定不可能である。一方でGoのチャネルのように厳密にタイミングを得られる仕組みもあるので、それを使うべきかどうか。

eihigheihigh

というかカメラを例にとるとチャネルというよりロックをとる方がイメージ近いかもしれない。

ロックかあー…難しいすなあ。

タイムアウトはもちろんのこと、ロック待ちになってるオブジェクトが何も出来ない時間が発生するので、それをどうユーザーに説明するかまで考えなければならない。

eihigheihigh

ツクールの並行処理イベントで天候を操作することができるが、複数のイベントが実行されたら望んだ天候にならないかもしれないとか、そういうの

eihigheihigh

オブジェクトがカメラを操作するのではなく、カメラが状態を見に行くという解決策もあるが、どこまで適用可能かはわからない。全部こちらに寄せるなら、書き込みは自分のオブジェクトに対してのみ行えるが、読み込みは他のオブジェクトに対して行えるという制約を課す。

非正規化的なアプローチ。同じ状態を一箇所で集中管理することができないのが欠点。

eihigheihigh

依存の制御は一般解がないしプログラマーが考える必要がある、ではプランナーが担当できるのはどこまでか?(依存の制御と切り離して作れるのはどこまでか?)

eihigheihigh

オブジェクトがシグナルを発火する、で統一するとかが無理なのが難しい

投げっぱなしではなく待ちが発生したりあるいは受ける側が観測すべき案件かもだし

eihigheihigh

とりあえずエフェクト部分はシンプルなFSMでいい、これだけでも十分大きい

物理演算で完結する部分もFSMで書ける。

UIだったり、物理演算に一手間加えようとすると破滅が始まる、、、。

eihigheihigh

オブジェクト自身の状態の変更は、一見依存を産まないように見えるが、他のオブジェクトが自身に書き込んでくる場合がある。これを考慮するのは大変なので避けたい。どうするか?

eihigheihigh

エフェクトは初期状態から時間発展することだけを考えればいいので、他者からの影響を考える必要はない。こういうのは明確に独立しており簡単。

eihigheihigh

また、以下のケースは他者からの影響であっても考慮する部分が少なくて済む

  • 上述の、初期状態が与えられたらあとは自由なもの
  • 強制的に進行を停止させられるもの(メニュー画面中など)
  • 強制的に削除させられるもの

逆にいうと、これら以外は考慮することが増えて大変。

eihigheihigh

「他者を観測して自身の挙動を変える」までがプランナーの仕事のような気がする。となるとカメラやBGMの制御は(少なくともオブジェクトがカメラを操作するという形では)プランナーに任せておけないということになる。それは確かにそうかも。

eihigheihigh
  • 割り込み(オブジェクトが他のオブジェクトの状態に干渉する):プログラマーが制御
  • 観測(他のオブジェクトの状態を見て自身の挙動を変える)、オブジェクトの生成と削除:プランナーが制御
eihigheihigh

割り込みが望ましいのに観測にしてしまう、あるいはその逆、のミスはありうるか?TODO: 以下に具体例を記載

eihigheihigh

そして「オブジェクトが他のオブジェクトに干渉する」ことが必要な処理をゲーム開発の文脈で昔からシーンと呼び習わしていたんじゃないかなあ、という霊感。

eihigheihigh

「ある状態に対して複数が書き込む」ことは問題になることもあるしならないこともある、むしろならないことの方が多いので問題に気づきづらい

eihigheihigh

オブジェクトに介入する処理をプログラマーが書く。オブジェクトは介入されることを意識せずに済むようにして開発速度を上げる。物理演算で何かにぶつかって押し戻されるのも「介入」の一種。

eihigheihigh

シーン遷移してもオブジェクトが矛盾を起こさないための方法は非常に限られていると考える。つまりオブジェクトの更新を一切止めるか、そのまま何の入力も受け付けずに消えるか。

eihigheihigh

オンラインゲームなら失敗を常に織り込んでいるはずなのでまた少し違うが、要はエラーハンドリングが増える。そのエラーハンドリング部分はプログラマーの領分になるだろう

eihigheihigh

Scratchのようなビジュアルプログラミング程度の能力を持った言語でゲームを作れるというのと、規模が大きくなってきたときにそこに秩序を持ったプログラムを組み合わせられるようにするのと二つの要素があるだろうか

このスクラップは2023/01/05にクローズされました