2012-04-08 14 views
0

私はRTSゲームを作成しています。ユーザアクションを「コマンド」にカプセル化したいと思います。コマンドができるようになる:RTSゲームのコマンドシステム

  • 他のプレイヤーにネットワーク経由でユーザーアクションを送信するので、すべての他の人が実行を防ぐために前に各アクションを有効にリプレイ機能
  • を有効にするには、ファイルへ
  • 記録ユーザーアクションをやっていることを知っています例えば、UIの変更(カメラの移動)、ゲーム状態の変更(ユニットの移動)、マップエディタのみが発行可能な操作地形)など

また、最小のオーバーヘッドを追加する必要があります。私はこのためにリフレクションを使用しないでください。 これまでのところ私が思いついたのは、必然的に巨大なswitch文で終わってしまうからです。

enum CommandType { 
    MoveCamera, 
    ChangeTerrain 
} 

// Base class for all commands (public fields used for brevity) 
abstract class Command { 
    protected Command(CommandType type) { 
     Type = type; 
    } 
    public CommandType Type; 
} 

class CommandMoveCamera : Command { 
    public CommandMoveCamera() : base(CommandType.MoveCamera) {} 
    public int DeltaX; 
    public int DeltaY; 
} 

class CommandChangeTerrain : Command { 
    public CommandChangeTerrain() : base(CommandType.ChangeTerrain) {} 
    public int NewTerrainType; 
    public int X; 
    public int Y; 
} 

class Game { 
    Queue<Command> m_commands; 
    void Update() { 
     // Example of adding a command 
     m_commands.Enqueue(new CommandMoveCamera { DeltaX = -10, DeltaY = 0 }); 

     // Processing commands 
     while (m_commands.Count > 0) { 
      var c = m_commands.Dequeue(); 
      switch(c.Type) { 
      case CommandType.MoveCamera: 
       var command = (CommandMoveCamera)c; 
       MoveCamera(c.DeltaX, c.DeltaY); 
       break; 
      case CommandType.ChangeTerrain: 
       var command = (CommandChangeTerrain)c; 
       ChangeTerrain(c.X, c.Y, c.NewTerrainType); 
       break; 
      } 
     } 
    } 
} 

言語はC#です。私の質問は、要件を満たす方法でこのシステムを実装し、巨大なswitch文に依存することを避けて、どのような方法でコマンドを実行するのでしょうか?

ありがとうございます。

+1

あなたのコードに目を向けたいのであれば、[codereview](http://codereview.stackexchange.com)があなたの質問のためのより良い家になるでしょう。さもなければ、あなたがコードを掲示したときの問題に特有です。 –

+0

私はコードのレビューを求めていませんが、コードは私が達成しようとしていることを説明するためのものです。私が探しているのは、私が述べたさまざまな要件を満たすことができる一方で、巨大なswitch文を避けるようにこのシステムを設計する方法です。 – Asik

+1

それは、SOの意図ではありません。あなたのシステムを設計する人が必要な場合は、お金を払うことを好む仕事のソフトウェアデザイナーがたくさんいると確信しています。真剣に、しかし、あなたの質問は、おそらく、ゲームサイトや別のフォーラムを試してみてくださいに適していません。 –

答えて

0

私にはいくつかのアイデアがあります。まず、コマンドの種類ごとにOn<Event>メソッドを公開することができます。次に、パラメータGameを使用してに抽象メソッドを追加します(Executeなど)。各コマンド実装は、Game(コマンドに関連する他のロジックを含む)上の適切なメソッドを呼び出すことができます。あなたはもはやenumを必要としません。

もう1つのアイデアはやや似ていますが、代理人を使用します。コマンドタイプごとにデリゲートを定義し、各コマンド実装に対して、このデリゲートを使用するイベントを公開します。次にCommand抽象で​​、メソッドExecuteを使用できます。このメソッドを実装すると、適切なイベントが発生します。各イベントを作成するときは、そのコマンドを処理するメンバーにGameのイベントを委任するだけです。

+1

私はあなたの提案と一緒に行くつもりです。同様の方法で二重ディスパッチの問題を解決するVisitorパターンを思い出させます(あなたに電話して、オーバーロードによって適切な型のメソッドを呼び出すように指示します)。とりあえずありがとう! – Asik

0

私はずっと前にゲームエンジンによく似たことをしました。私は実際にいくつかの異なるバージョンを使いました。私が思いついたのは、このようなものでした。

  • すべてのコマンドは、すべてのコマンドがCommandRegistryに登録する必要があり、そのためCommandRegistry各コマンドのためのユニークなIDを持っている(シリアライズされ意味)コマンドインタフェース
  • を実装します。

次に、コマンドラインを介してコマンドを送信するには、CommandRegistryにシリアル化を依頼します。それはコマンドをシリアル化し、そのIDを指し示します。受信側のCommandRegistryはIDを読み取り、適切な型のコマンドを作成し、残りのデータから自身を逆シリアル化するように要求します。

私はC++とGoの両方でこの基本設定を行ったので、C#でうまく動作するはずです。

+0

私はこれに似ていますが、IDを知っている適切なタイプのコマンドをどのように作成しますか?これまで私が見つけたのは、最終的には維持不能なswitch文を構築することだけでした。 C++では、テンプレートと関数ポインタを使用することができましたが、C#でどのように可能かはわかりません。 – Asik

+0

私はその特定の部分を行うためにあなたの言語のリフレクションを使用しますが、それが実行可能かどうかを知るのに十分にC#は分かりません。リフレクション以外の最も簡単なことは、登録時に、適切な型を作成して抽象クラスとして返す関数への関数ポインタを渡すことです。レジストリは、Idから関数ポインタへのマッピングを維持するので、必要なときにいつでも作成できます。 –

+0

Wildを実行していただきありがとうございます。私はこれらの2つについて考えましたが、C#のリフレクションは私のニーズには遅すぎるので、 "関数ポインタ"(デリゲート)は強く型付けされているので、ベースタイプを使用しない限り、異なるシグネチャを持つデリゲートを一緒に保存する方法はありませんそれは問題を戻すだけです)。 – Asik

関連する問題