make-everything-static-and-globalデザインパターンを取り除きたいのですが、どうすればいいですか?


11

私は宇宙で小さなダンジョンクローラーを作っています。エンジンのバックエンドをより良くする方法についてのアドバイスを聞きたいです。基本的に、現在はすべてが管理者のがらくたに基づいています:

  • BackgroundManager:AddBackground(image, parallax)クールな背景効果を作成するためのメソッドがあります。
  • ConfigManager:構成ファイルを読み取り/作成し、その構成ファイルから読み取ったデータも保持します。
  • DrawManager:持っているDraw(sprite)画面にコンテンツを描画する方法を、そして物事が好きSetView(view)GetView()など
  • EntityManager:すべてのアクティブなエンティティを保持し、エンティティを追加、削除、検索するためのメソッドを備えています。
  • DungeonManager(実際GridManagerと呼ばれるが、これは簡単にするためである):のようなメソッドがありGenerateDungeon()PlaceEnemies()PlaceFinish()など

現在、私はすべてのマネージャーをリストアップしているわけではないので、これは変化しなければならないと思います。私のゲームもスクリーンに基づいていますが、メインメニューなど、マネージャーが管理しているものの半分が必要ないため、面倒です(メインメニューには物理学/エンティティ/ダンジョンは必要ありません!)

ここで、マネージャーを静的ではなく、ScreenMainGameにすべてのゲーム固有マネージャーのインスタンスを与えることを考えました。しかし、それはマネージャーに関連するものを呼び出したり取得したりするのを巨大な混乱にScreenMainGame.Draw()させます...

((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()

それは本当にいです。

それで、仲間のゲーム開発者は、この混乱を解決する方法を知っていますか?ありがたいです!


私はあなたをどのように助けるのか正確にはわかりませんが、デザインパターンに関する良い本を読むことをお勧めします。私はHead First Design Patternsを読んでいますが、とても理解しやすいです。例はJavaにありますが、C#に十分に近いと思います。私の提案が初心者すぎる場合は申し訳ありません。
Amplify91

グラフィックカードとのインターフェイスに何を使用していますか?XNA?SlimDX?
BlueRaja-ダニーPflughoeft

@BlueRaja:SFML.NETを使用しています。
ドラー

その場合は、C#でこれらの問題を処理する通常の方法を使用する必要があります。次の最後のリンクと依存関係注入とは何ですか?
BlueRaja-ダニーPflughoeft

回答:


10

何についてのコンポーネント・ベースのエンジン

という名前のメインクラスがあり、EngineリストをGameScreens保持しますComponents

エンジンはありUpdate及びDraw方法との両方のコールGameScreenさんUpdateDraw自身がすべてのコンポーネントとコールを経る方法、UpdateおよびをDraw

そのように提示されると、それは貧弱で反復的なデザインのように聞こえることに同意します。しかし、私を信じてください。私のコードは、コンポーネントベースのアプローチを使用することで、以前のすべてのマネージャークラスよりもずっときれいになりました。

このようなコードを維持する方がはるかに簡単です。なぜなら、大きなクラス階層を通過するだけでBackgroundManager、特定の異なる背景をすべて検索する必要がないからです。あなただけの持っているScrollingBackgroundParallaxBackgroundStaticBackground、などから派生したすべてのBackgroundクラス。

最終的には、非常に堅牢なエンジンを構築し、頻繁に使用するコンポーネントとヘルパーメソッド(たとえばFrameRateDisplayer、デバッグユーティリティ、Spriteテクスチャ付きの基本スプライトとしてのクラス、ベクトルの拡張メソッドなど)を使用してすべてのプロジェクトで再利用できます乱数生成)。

BackgroundManagerクラスはもうありませんが、Background代わりに自分自身を管理するクラスがあります。

ゲームが開始されたら、基本的に次のことだけです:

// when declaring variables:
Engine engine;

// when initializing:
engine = new Engine();
engine.Initialize();
engine.LoadContent();
engine.AddGameScreen(new MainMenuScreen());

// when updating:
engine.Update();

// when drawing:
engine.Draw();

これでゲーム開始コードは終わりです。

次に、メインメニュー画面の場合:

class MainMenuScreen : MenuScreen // where MenuScreen derives from the GameScreen class
{
    const int ENEMY_COUNT = 10;

    StaticBackground background;
    Player player;
    List<Enemy> enemies;

    public override void Initialize()
    {
        background = new StaticBackground();
        player = new Player();
        enemies = new List<Enemy>();

        base.AddComponent(background); // defined within the GameScreen class
        base.AddComponent(player);
        for (int i = 0; i < ENEMY_COUNT; ++i)
        {
            Enemy newEnemy = new Enemy();
            enemies.Add(newEnemy);
            base.AddComponent(newEnemy);
        }
    }
}

あなたは一般的なアイデアを得る。

また、クラス内でも新しい画面を追加できるように、EngineすべてのGameScreenクラス内の参照を保持しますGameScreen(たとえば、内でユーザーがStartGameボタンをクリックすると、にMainMenuScreen移行できますGameplayScreen)。

Componentクラスについても同じことが言えます。クラスの親の参照を保持しGameScreenて、Engineクラスとその親GameScreenへのアクセス権を持たせ、新しいコンポーネントを追加する必要があります(たとえばDrawableButtonDrawableTextコンポーネントとコンポーネントを保持する HUD関連クラスを呼び出すことができStaticBackgroundます)。

その後、他のデザインパターンを適用することもできます。たとえば、「サービスデザインパターン」(正確な名前はわかりません)のように、Engineクラス内にさまざまな有用なサービスを保持IServiceできます)。たとえば、Camera2D他のコンポーネントを描画するときにその変換を適用するサービスとして、すべてのプロジェクトでコンポーネントを保持します。これにより、パラメータとしてどこにでも渡す必要がなくなります。

結論として、エンジンには他にも優れた設計があるかもしれませんが、このリンクで提案されているエンジンは非常にエレガントで、非常に簡単に保守および再利用できます。個人的には、少なくとも試してみることをお勧めします。


1
XNAは、GameComponentsおよびサービスを介して、これらすべてをそのままサポートしています。別のEngineクラスは必要ありません。
BlueRaja-ダニーPflughoeft

この回答の+1。また、ゲーム更新スレッドとは別のスレッドに描画を配置するのは理にかなっていますか?
f20k

1
@BlueRaja-DannyPflughoeft:確かに、XNAは使用されていないと思っていたので、その方法についてもう少し説明しました。
ジェシーエモンド

@ f20k:はい、XNAの場合とほぼ同じです。しかし、どのように実装されているのかわかりません。= /インターネット上のどこかに、その方法についての記事がなければなりません。:)
ジェシーエモンド

ええ、私はXNAを使用していませんが、これは私がやっていることの素晴らしい代替案のようです。現在、「Head First Design Patterns」という本を読んで、他に選択肢があるかどうかを確認しています。乾杯!
ドラー


-3

静的またはグローバルであるからといって、常にロード/初期化する必要があるわけではありません。シングルトンパターンを使用して、マネージャーを解放可能にし、必要に応じて再度ロードできるようにします。


4
シングルトンは、OPがここで解決しようとしている根本的な問題の正面にすぎません。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.