web-dev-qa-db-ja.com

MVCパターンに合うようにゲームのコードをどのように整理できますか?

私はコンピュータサイエンスの学位を取得するために大学の新入生です。ここ数年はたくさんプログラムしてきましたが、最近、コードの編成、デザインパターン、言語の違いなどについての理論的なアイデアについて詳しく知りました。

私はJavaクラスを持っているので、C++の研究/開発を中止し、JavaとJOGL(Java OpenGL)に移動しました。すばらしいです!しかし、それはポイントの横に。

小さなロールプレイングゲームを作成したいのですが、この質問はどのようなゲームにも当てはまります。 Model-View-Controllerパターンのような構造化された方法でゲームオブジェクトをどのように整理しますか?それは非常に広く使用され、非常に理にかなっている素晴らしいパターンのように見えますが、それを実装する方法を理解するのに苦労しています。

たとえば、画面に描画するためのGLオブジェクトを追跡する必要があります。MouseListener、MouseMotionListener、MouseWheelListener、およびKeyListenerを実装するクラス(または1つのクラス、all- 1つの入力マネージャーです。また、ゲームデータをこれらのさまざまなクラスすべてがアクセスおよび変更できる場所に配置する必要があります。誰かがキーボードのボタンを押した場合、入力管理クラスは何らかの方法でキーのアクションを実行する必要がありますマップ先;フレームを描画する必要がある場合、グラフィックスクラスは、さまざまな「もの」すべてをループしてそれらをすべて描画する方法を見つける必要があります。

そして、私の最大の問題はGUIです。それはどこにそれを結びつけますか?これは入力のようなものですが、完全ではありません。実際のゲームシミュレーションからデータの一部を設定および取得する必要があります。さらに、ネットワークを追加しようとすると、さらに複雑になります(GUIに似ています)。 )また、変更や読み取りのために多くのデータにアクセスできる必要があります...

ああ、私はすべて混乱しています。これらすべてをオブジェクト指向の方法で一緒に機能させる方法はわかりません...パターンに明確に一致するものを書くのは簡単ですが、発生する多くのことがすべて1つのゲームループに関連付けられている場合は、お互いを変更しますゲームのデータなど…もう知りません。多分私はこれを実際よりも大きな取引にしているだけかもしれません。

他の誰かがこのように感じましたか?心配する必要がなく、どこから始めればよいかわからないように、状況を明確にしてください。

-リケット

編集:これをすべて理解するのに役立つ素敵な図を見つけました...ソース:(注意、PSファイル!) http://www.tucs.fi/publications/attachment.php?fname=TR553。 ps.gz

http://img10.imageshack.us/img10/6278/mvcdiagramgamesbl5.png

Edit2:私はこの男がどのようにMVCゲームを計画したかについての説明も気に入っています: http://interactivesection.wordpress.com/2007/11/19/dum-de-dum-drum-my-first-mvc-ゲーム開発/

Edit3:別の素晴らしい記事! http://dewitters.koonsolo.com/gamemvc.html

71
Ricket

これは、モデルを一種のゲームAPIと考えるのに役立ちます。最初から定められたゲームのUIがまったくない場合、あなたのゲームは何に縮小されますか?あなたが心に描いているのはRPGであると述べたので、この場合、プレイヤーキャラクター、彼/彼女のインベントリ、呪文、能力、NPC、さらにはマップや戦闘ルールなどすべてがモデルの一部であると想像できます。 。それは、最終的なゲームがそれをどのように表示するか、またはユーザーがどのように操作するかについての詳細のない、モノポリーのルールと断片のようなものです。それは、交差、衝突などが計算され、レンダリング、影、または音響効果がないレベルで移動する3Dオブジェクトの抽象的なセットとしてのQuakeのようなものです。

これらすべてをモデルに組み込むことで、ゲーム自体はUIに依存しなくなります。 ASCII Rogueのゲームのようなテキストインターフェイス、またはZorkに似たコマンドラインUI、Webベース、または3D UIにフックできます。これらのUIのいくつかはひどいフィットかもしれませんゲームの仕組みによって異なりますが、すべて可能です。

ビューレイヤーは、UIに依存するレイヤーです。これは、使用したUIの特定の選択を反映しており、そのテクノロジに非常に特化しています。モデルの状態を読み取り、それを3D、ASCII、またはWebページの画像とHTMLで描画する必要があります。また、プレーヤーがゲームと対話するために使用する必要のある制御メカニズムを表示する役割もあります。

コントローラレイヤは、2つの間の接着剤です。その中に実際のゲームロジックが含まれていてはならず、ビューレイヤーを駆動する責任もありません。代わりに、ビューレイヤーで行われたアクション(ボタンのクリック、画面の領域のクリック、ジョイスティックのアクションなど)をモデルで行われたアクションに変換する必要があります。たとえば、アイテムのドロップ、NPCへの攻撃など。また、データを収集し、ビューレイヤーでデータを表示しやすくするための変換や処理を行います。

さて、上記で説明した方法は、ゲームを駆動する非常に明確なイベントシーケンスがあり、おそらくWebゲームにのみ適切であるかのようです。それは私が最近私の時間を費やしたものだからです。ユーザーの要求とWebのようなサーバーの応答によって駆動されないゲーム(たとえば、ユーザーのマシンで実行されているゲーム)では、モデルレイヤーがObserverパターンを適切に実装していることを確認する必要があります。たとえば、時間が経過しているためにモデルでアクションが発生する場合は、ビューレイヤーに更新のために絶えずモデルをポーリングさせたくない場合があります。代わりに、オブザーバーパターンを使用することにより、モデルは、オブザーバーにModelオブジェクトの変更が発生したときに通知することができます。これを使用して、ビューを即座に更新し、変更を反映させることができます。

次に、60秒経過した結果、プレイヤーのベースに修理が行われた場合、ベースは修理に影響を与え、アタッチされているオブザーバーにベースが更新されたことをすぐに通知できます。ビューはオブザーバーとして接続でき、状態が変化したため、ベースを再表示する必要があることに注意してください。通知自体に、ビューを更新するのに十分な情報が含まれているか、更新のためにモデルを参照して確認する必要があるかもしれませんが、結果は同じです。

56
John Munsch

あなたはそこにやっています。基本的に、「プログラムの一部を変更しなければならない場合、どのコードが変更されるのか」という質問を自問してください。

基本データを変更せずに外観が変わる場合は、ビュー内にあります。さまざまな方法で表示できるデータであれば、それはモデルです。そして、それがあなたのプレーの仕方なら、それはコントロールです。

つまり、2つのブレードまたは1つのブレードで「斧」を描くかどうかは、ビューです。それがあなたが斧で与えたダメージのヒットポイントの数であれば、それはモデルです。そして、「s」を入力するか、右クリックして斧を振るかどうかは、コントロールです。

19
Charlie Martin

私が最初にMVCを発見したとき、私はすべてをそれに詰め込もうとしたことを覚えています。確かにMVCパターンを利用したゲームを作りました。後で見つけたのは、私がやったのはやり過ぎだったということです。私はMVCの1つのカテゴリに作成したほぼすべての単一クラスを適合させようとしました。

私が提案するのは、4人一組の「デザインパターン」を読むことです。 MVC以外にも多くの便利なパターンがあります。 MVCを使用してもまったく意味がない場合があります。特にゲームの場合、MVCがこれほど優れているかどうかはわかりません。その理由は、ゲームオブジェクトをさまざまな方法(ビュー)で表示するのではなく、さまざまな種類のゲームオブジェクトで描画コードを再利用するためです。

私自身の2Dゲームエンジンでは、戦略パターンをかなり積極的に使用しました。プレイヤーや私がSpriteと呼んだモンスターのようなゲームオブジェクト。スプライトの描画は戦略パターンで処理します。それは私がSprite.draw()を呼び出したときです私はこのようなことをします:

class Sprite {
  void draw() {
    this.view.draw(this.currentPosition, this.currentOrientation);
  }

  Point  currentPosition;    // Current position of this Sprite
  double currentOrientation; // Facing angle of Sprite
};

このアプローチの利点は、複数のスプライト間でビューオブジェクトを共有できることです。なぜなら、多くの場合、たとえば同じに見えるが、位置が異なり、動作が異なる可能性があるモンスター。

ですから、私はビヘイビアを記述するコードを含むオブジェクトである戦略パターンも使用します。そうすれば、同じ場所にいる複数のモンスターに同じ動作を適用できます。したがって、フレームごとにpdate()関数を呼び出して、位置の向きとモンスターの動作を更新します。

class Sprite {
  void setUpdateAction(Action action) {
    this.updateAction = action;
  }

  void update(double start_time, double delta_time)
  {
    this.prevPosition = position();  
    advance(delta_time); // Advance to next position based on current speed and orientation

    this.updateAction.execute(this, start_time, delta_time);
  }

  Action updateAction;
};

これにはさまざまなバリエーションがあります。私の現在の実装では、currentPositionspeedorientationおよびadvance()を別のオブジェクトに分離していますMotionStateと呼ばれます。これは、パス検索アルゴリズムを実行するときに、可能な位置と方向の検索ツリーを構築できるようにするためです。次に、各更新の動作方法やSpriteの描画方法に関する情報を持ち歩きたくありません。

8
Erik Engheim

ユーザーインタラクションロジックを集中管理するというMVCの概念は、ゲーム開発に適したモデルです。

Flashゲーム開発で少し作業を行いました。 ここ は、Flashのオブジェクトプールに関する記事です。概念はクロスプラットフォームであり、いくつかのアイデアを与える可能性があります。

あなたは一度に起こっているすべてのものに関心があるのは当然です。ゲームのデザインによっては、ゲームのループに対処することがたくさんあります。ここでは、すべてのダーティな最適化のトリックを学びます。多くの場合は難しい方法です。)

コードを整理するには多くの方法があります。1つのオプションは、GameManagerクラスをシングルトンとして記述することです。すべてのゲームオブジェクトは、管理とユーザー操作のためにそれに関連付けられます。 GameManagerはすべてのユーザー入力を処理し、そのオブジェクトプールにメッセージをディスパッチします。インターフェイスを使用して、ゲームオブジェクトとGameManagerの間の一般的な通信パターンを定義できます。

パフォーマンスの最適化に関する限り、スレッド化は非常に強力です。非同期操作により、これらの貴重なサイクルを無駄にしないことが保証されます。

2
Dave Swersky

すべてのリスナーとハンドラーはコントローラークラスの内部に移動する必要があり、画面上のオブジェクトの状態(位置、色など)はモデルクラスの一部であり、画面に描画するコードはすべてその一部になります。景色。

1
Rocket Surgeon

MVCの私の考え方はMDUCと同じです
モデル
表示
ユーザー入力コントローラー

モデルにはドメインモデルオブジェクトが含まれています
画面には、ドメインモデルオブジェクトの現在の状態と動作が画面に表示されます。
ユーザー入力コントローラは、すべてのユーザー入力を処理します。

まったく同じパターンですが、名前が少しだけわかりやすくなっているので、パターンの各部分の責任がより明確になり、パターンの意味がより覚えやすくなります。

ユーザーの入力から、データとモデルの操作を表示から分割していることがわかると、独自のコードのどこに何をグループ化するかを簡単に確認できます。

1
Euan M