純粋な関数型プログラミングとゲームの状態


12

関数型プログラミング言語で(一般に)状態を処理する一般的な手法はありますか?グローバル状態を処理するためのすべての(機能的な)プログラミング言語には解決策がありますが、できる限りこれを避けたいと思います。

純粋に機能的な方法でのすべての状態は、機能パラメーターです。そのため、特定の入力またはトリガーで世界を操作するすべての関数のパラメーターとして、ゲーム全体の状態(世界、プレイヤー、ポジション、スコア、アセット、敵などの巨大なハッシュマップ)を配置する必要があります。関数自体は、gamestate blobから関連情報を選択し、それを使用して、gamestateを操作し、gamestateを返します。しかし、これは問題に対する貧弱な解決策のように見えます。ゲームステート全体をすべての関数に入れた場合、グローバル変数や命令型アプローチとは対照的に、私にとってメリットはありません。

関連する情報だけを関数に入れて、指定された入力に対して実行されるアクションを返すことができます。そして、1つの関数がすべてのアクションをgamestateに適用します。しかし、ほとんどの機能には多くの「関連する」情報が必要です。move()オブジェクトの位置、速度、衝突のマップ、すべての敵の位置、現在のヘルスなどが必要です。したがって、このアプローチも機能しないようです。

私の質問は、関数型プログラミング言語で膨大な量の状態をどのように処理するのか、特にゲーム開発の場合ですか?

編集: Clojureでゲームを構築するためのゲームフレームワークがいくつかあります。この問題を部分的に解決するアプローチは、ゲーム内のすべてのオブジェクトを「エンティティ」としてスレッド化し、巨大なバッグに入れることです。ギガント主な機能は、画面を保持しているし、エンティティとハンドルイベント(:on-key-down:on-initこのエンティティのため、...)とは、メインディスプレイのループを実行します。しかし、これは私が探しているクリーンなソリューションではありません。


私はしばらくの間、この種のことを考えていました。私にとって、それは入力であり、ユニークな問題ではありません。非機能プログラミングの関数に同じ要素を(おおよそ)フィードしなければならないからです。いいえ、問題は出力(および関連する更新)です。入力パラメーターの一部を組み合わせる必要があります。のためにmove()、あなたはおそらく「現在の」オブジェクト(またはその識別子)に加えて、それが通過する世界を渡して、単に現在の位置と速度を導出する必要があります...出力は物理世界全体、または少なくとも変更されたオブジェクトのリスト。
時計仕掛けのミューズ14

純粋な関数の利点は、関数プロトタイプがプログラムにあるすべての依存関係を示すことです。
tp1 14

3
IMO、関数型言語はゲームの作成にはあまり適していません。これは、解決する必要がある多くの問題の1つです。ゲームでは、イベントが自然に発生する予測不可能な方法のため、パフォーマンスを非常に正確に制御する必要がありますが、同時実行性はほとんどありません。(純粋な)関数型言語は、些細な並列化が可能で、最適化が難しいことで有名です。ゲームは書くのが難しいので、同じくらい複雑なもの(関数型プログラミング)を始める前に、典型的な言語でそれをすることをお勧めします。
ケーシークーボール14

回答:


7

関数型プログラミング言語の副作用と状態は、コンピューターサイエンスの広範な問題です。以前にそれらに遭遇したことがない場合は、おそらくモナドを見てください。ただし、注意してください。それらはかなり高度な概念であり、私が知っているほとんどの人(私も含む)はそれらを把握するのに苦労しています。さまざまなアプローチと知識要件を備えた多くのオンラインチュートリアルがあります。個人的には、Eric Lippertの最高が好きでした。

私は「関数型プログラミング」のバックグラウンドがまったくないC#プログラマーです。私がよく耳にするこの「モナド」とは何ですか?

MonadsのEric Lippert

ただし、考慮すべき事項がいくつかあります。

  • 純粋に機能的な言語の使用を主張していますか?もしあなたが関数型プログラミングとゲーム開発の両方に熟練していれば、それをやってのけるかもしれません。(たとえ利益が努力に値するかどうかを知りたいのですが)
  • 必要な場合にのみ機能的なアプローチを使用する方が良いと思いませんか?オブジェクト指向(または、より多くの場合、マルチパラダイム)言語を使用している場合、機能的なスタイルを使用してそれから利益を得るセクションを実装することを妨げるものは何もありません。(KindaはMapReduceのようなものでしょうか?)

いくつかの最終的な考え:

  • 並列処理:ゲームそれを頻繁に使用ますが、そのほとんどはGPUで既に発生しています。
  • ステートレス:状態の変化はゲームの不可欠な部分です。それらを取り除こうとすると、問題が不必要に複雑になるだけです。
  • 興味のある方は、関数型言語F#が.NETのオブジェクト指向エコシステムでどのように機能するかを見てください。

全体として、学問的に面白くても、このアプローチは実用的であり、努力する価値があるとは思いません。


経験のないテーマについてコメントを投稿するのはなぜですか?思考のパラダイムに閉じ込められた人々からの意見。
アンソニーライモンド

4

FOP(マルチパラダイム、不純、機能優先言語)を使用して、OOPからFRPまでのアプローチでいくつかのゲームを作成しました。これは幅広い質問ですが、最善を尽くします。

関数型プログラミング言語で(一般に)状態を処理する一般的な手法はありますか?

私の好ましい方法は、ゲーム全体を表す不変の型を持つことStateです。その後、Stateティックごとに更新される電流への可変参照があります。これは厳密に純粋ではありませんが、可変性を1つの場所に制限します。

ゲームステート全体をすべての関数に入れた場合、グローバル変数や命令型アプローチとは対照的に、私にとってメリットはありません。

違います。State型は不変であるため、不明確な方法で世界を変化させる古いコンポーネントを持つことはできません。これにより、このGameObjectアプローチの最大の問題(Unityで普及)が修正されます。Updateます。呼び出しです。

また、グローバルを使用する場合とは異なり、簡単に単体テストと並列化が可能です。

また、状態のサブプロパティを受け取って問題を解決するヘルパー関数を作成する必要があります。

例えば:

let updateSpaceShip ship = 
  {
    ship with 
      Position = ship.Position + ship.Velocity
  }

let update state = 
  { 
    state with 
      SpaceShips = state.SpaceShips |> map updateSpaceShip 
  }

ここupdateでは、状態全体にupdateSpaceShip作用しますが、個別SpaceShipに単独で作用します。

関連する情報だけを関数に入れて、指定された入力に対して実行されるアクションを返すことができます。

私の提案はInput、キーボード、マウス、ゲームパッドなどの状態を保持するタイプを作成することです。その後、取る関数書くことができますStateし、Input次の返却をState

let applyInput input state = 
  // Something

これがどのように組み合わされるかを知るために、ゲーム全体は次のようになります。

let mutable state = initialState ()

// Game loop
while true do
  // Apply user input to the world
  let input = collectInput ()

  state <- applyInput input state

  // Game logic
  let dt = computeDeltaTime ()

  state <- update dt state

  // Draw
  render state

私の質問は、関数型プログラミング言語で膨大な量の状態をどのように処理するのか、特にゲーム開発の場合ですか?

シンプルなゲームでは、上記のアプローチ(ヘルパー関数)を使用できます。より複雑なものについては、「レンズ」。

ここでのコメントのいくつかに反して、(不純な)関数型プログラミング言語でゲームを書くか、少なくとも試してみることを強くお勧めします!繰り返しが速くなり、コードベースが小さくなり、バグが少なくなることがわかりました。

また、(不純な)FP言語でゲームを書くためにモナドを学ぶ必要はないと思います。これは、コードがブロッキングとシングルスレッドである可能性が高いためです。

これは、マルチプレイヤーゲームを作成している場合に特に当てはまります。そうすれば、ゲームの状態を簡単にシリアル化し、ネットワークを介して送信できるため、このアプローチでは事態がはるかに簡単になります。

これほど多くのゲームがこのように書かれていない理由については...私は言うことができません。ただし、これはすべてのプログラミングドメイン(金融を除く)に当てはまるため、関数型言語がゲームプログラミングに不向きであるという議論としてこれを使用することはありません。

また、Purely Functional Retrogamesも読む価値があります。


1

探しているのはFRPゲーム開発です。

いくつかのビデオ紹介:

コアゲームロジックを純粋に機能的な方法で作成することは100%可能であり、望ましいことです。業界全体は単に背後にあり、1つの思考パラダイムにとどまっています。

Unityでも同様に行うことができます。

質問に答えるために、何かが動くたびに新しいゲームの状態が更新/作成されます。カーマックが彼の講演で述べているように、それは問題ではありません。純粋に機能的で、メンテナンス性が高く、柔軟なアーキテクチャに起因する認知オーバーヘッドの大幅な削減は、パフォーマンスが存在するとしても、それがはるかに優れています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.