XNA GameComponents間(またはゲーム内の任意のタイプのコンポーネント間)の通信を容易にするためにどのテクニックを使用する必要がありますか?


9

私は最初の「適切な」ゲームプロジェクトから始めています。必然的に、XNAのゲームコンポーネントがどのように通信するかを決定しようとするブロックにぶつかりました。

以前の(Java)GUIプログラミングイベントから、ハンドラーとリスナーは前に進んだように見えました。ですから、イベントの登録とそれらのイベントにサブスクライブしたクラスを受け入れ、それらを処理するハンドラーを備えた、ある種のイベントバスがあります。例(疑似コード):

class SpriteManager
    Update(){
        if(player.collidesWith(enemy)
             // create new 'PlayerCollisionEvent'
    }

class HUDManager
    onPlayerCollisionEvent(){
        // Update the HUD (reduce lives etc)
    }

ただし、これを完全に達成するために必要なコード設定(C#で)はわかりません。イベントを追跡しているもの(ある種のバス?)とその構造は?

ゲームサービスについても多く言及されているようです。これにより、メインのGame.csクラスにGameComponentを登録し、メインの 'Game'オブジェクトへの参照を持つコードの任意の場所からフェッチできます。SpriteBatchオブジェクトでこれを試しましたが、非常に簡単に見えます。しかし、これがイベントモデルほど柔軟ではないことがわかります。

たとえば、敵が死亡した場合を考えてみましょう。ゲームのスコアを更新したい。サービスを使用して、Game1で作成され、サービスとして追加されたStateManagerオブジェクトへの参照を取得し、 'score'を新しい値に設定できます。「onEnemyDeath」イベントはさまざまなクラスで別々に処理できますが、関連する「敵の死の検出」セクションの1行のコードで開始され、必要な各GameComponentを個別にキャストしてから何でも呼び出すよりも良いと思いますメソッドが必要です。

それとも、これらは他の戦略よりも劣っていますか?

これは、ゲーム通信のパラダイムと同じくらい、私のC#知識が不十分であることの一部だと思いますが、この基本的なことを正しくしたいのですが。

更新

サービスを確認したことの方が詳細であると私は確信していません。これは、基本的に(私が理解しているところから)グローバル変数を渡すことです。

アップデート2

イベントの処理とサンプルコードのテストに関するこの基本的なチュートリアルを見てきたので、私が議論しているのはイベントが論理的な選択になると思われます。しかし、私が見たサンプルでそれを使用することはあまりできません。すべきでない明白な理由はありますか?


最初にFlatRedBallを試すことをお勧めします。XNAの上に配置されており、非常に使いやすくなっています。
ashes999 '10

3
エンジンにジャンプする前に、何が起こっているのかについての基本を本当に理解したいと思います。
codehands、2011年

ここでの失敗は本当にC#に関する情報の欠如だと思います。C#は通常、クラス間の通信を容易にするためにイベントを使用します。実際にどのように行うかはあなた次第です。XNAはSpriteBatchクラスを提供し、ほとんどの作業はユーザーが作成する必要があります。エンジンは、詳細に入る前に、物事がより高いレベルでどのように機能するかについての確固たるアイデアを提供します。
灰999

1
私はある程度同意しますが、読んだところから、GameComponent間のクラス間通信のほとんどはサービスを使用して行うことができます。私はイベントに慣れています。私は最善であるかわからないんだけど、または有効な代替案(シングルトン、私は省略してきた2つの他の方法として、グローバルになりすまし静的クラス)がある場合
codinghands

回答:


4

以前の(Java)GUIプログラミングイベントから、ハンドラーとリスナーは前に進んだように見えました。ですから、イベントの登録とそれらのイベントにサブスクライブしたクラスを受け入れ、それらを処理するハンドラーを備えた、ある種のイベントバスがあります。

C#でイベントバスについてあまり理解できないのは、私の経験上、Javaの外部の誰もそのようなものを「バス」とは考えていないためです。より一般的な用語は、メッセージキュー、イベントマネージャー、シグナル/スロット、パブリッシュ/サブスクライブなどです。

動作するゲームを作成するためにそれらは必要ありませんが、それが使いやすいシステムの種類であれば、ここでもうまく機能します。残念ながら、誰もがまったく使用しない場合でも、ロールの仕方が少し異なるため、誰がどのように作成するかを正確に伝えることはできません。(たとえば、私はしません。)System.Collections.Generic.List<Event>キューの単純なものから始め、さまざまなイベントをEventのサブクラスにして、各イベントタイプのサブスクライバーのリストを作成します。キュー内のイベントごとにサブスクライバーのリストを取得し、サブスクライバーごとに呼び出しますhandle(this_event)。次に、それをキューから削除します。繰り返す。

ゲームサービスについても多く言及されているようです。これにより、メインのGame.csクラスにGameComponentを登録し、メインの 'Game'オブジェクトへの参照を持つコードの任意の場所からフェッチできます。SpriteBatchオブジェクトでこれを試しましたが、非常に簡単に見えます。しかし、これがイベントモデルほど柔軟ではないことがわかります。

おそらくそれほど柔軟ではありませんが、デバッグは簡単です。イベントとメッセージは、呼び出し元の関数から呼び出し元の関数を分離するため、トリッキーです。つまり、デバッグ時に呼び出しスタックがあまり役立たないため、中間のアクションにより、通常は機能する何かが中断され、適切に接続されていない場合、何もせずに失敗する可能性があります。 、 等々。「コンポーネントを取得して必要なものを呼び出す」という明示的な方法は、早い段階でエラーをキャッチし、明確で明示的なコードを作成する場合に適しています。密結合されたコードと多くの複雑な依存関係につながる傾向があるだけです。

これは、ゲーム通信のパラダイムと同じくらい、私のC#知識が不十分であることの一部だと思いますが、この基本的なことを正しくしたいのですが。

C#はJavaとほとんど同じ言語です。Javaで行ったことは、C#でもさまざまな構文で実行できます。概念の変換に問題がある場合、それはおそらく、そのJava固有の名前しか知らないためです。


@Kylotanありがとうございます。好奇心から、あなたはクラス間コミュニケーションのためにあなた自身どのシステムを使用していますか-サービスアプローチか何か?
codehands、2011年

AFAIK、イベントバスはメッセージングキューのものに似ていますが、イベント用です。
ashes999

2
@codinghands、私は通常、形式化されたクラス間通信メソッドを使用しません。私は物事を単純に保ちます-あるクラスが別のクラスを呼び出す必要がある場合、通常、そのクラスにはすでに2番目のクラスへの参照がメンバーとして含まれているか、2番目のクラスが引数として渡されています。ただし、Unityエンジンを使用しているときに、「サービス」アプローチと呼んでいる方法と似た方法で、必要なコンポーネントを持つオブジェクトを名前で検索し、コンポーネントを検索する場合もあります。オブジェクトで、そのコンポーネントのメソッドを呼び出します。
Kylotan、2011年

@ ashes999-メッセージとイベントは、このコンテキストではほとんど同じです。イベントをキューやバスなどに配置した場合、実際に格納しているのは、イベントが発生したことを示すメッセージです。同様に、メッセージをキューに入れると、そのメッセージを生成するイベントが発生したことを意味します。非同期関数呼び出しのさまざまな見方。
カイロタン、

申し訳ありませんが、まだ「回答済み」とマークしていませんが、言語に関係なく、すべてのゲームがコンポーネント間で何らかの方法で通信する必要があるので、もっと多くの視点があると思いました...主な可能性をカバーしましたか?
コーディングハンズ

1

単純な静的イベントを使用してみましたか?たとえば、スコアクラスで敵がいつ死んだかを知りたい場合は、次のようにします。

Score.cs

class Score
{
    public int PlayerScore { get; set; }

    public Score()
    {
        EnemySpaceship.Death += new EventHandler<SpaceshipDeathEventArgs>(Spaceship_Death);
    }

    private void Spaceship_Death(object sender, SpaceshipDeathEventArgs e)
    {
        PlayerScore += e.Points;
    }
}

EnemySpaceship.cs

class EnemySpaceship
{
    public static event EventHandler<SpaceshipDeathEventArgs> Death;

    public void Kill()
    {
        OnDeath();
    }

    protected virtual void OnDeath()
    {
        if (Death != null)
        {
            Death(this, new SpaceshipDeathEventArgs(50));
        }
    }
}

SpaceshipDeathEventArgs.cs

class SpaceshipDeathEventArgs : EventArgs
{
    public int Points { get; private set; }

    internal SpaceshipDeathEventArgs(int points)
    {
        Points = points;
    }
}


0

このようなイベントアグリゲーターを使用してみてください


4
この回答は、リンクを提供するだけでなく、提案について詳しく説明した方がよいでしょう。
MichaelHouse
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.