13

2D XNA ゲームでスプライトを効率的に描画する方法は何ですか? より具体的にするために、この質問を 4 つの質問に分割しました。


以前は、Game1 の spriteBatch staticを宣言し、everyでSpriteBatch.Beginandを呼び出していました。それはうまくいきませんでした。各ドローアブルに独自の SpriteBatch を与えることもうまくいきませんでした。.CloseIDrawable.Draw

Q1 : SpriteBatch インスタンスを1 つ持ち、begin/closeを 1 回だけ呼び出すのが最善だと思います。これは正しいです?


現在、私のGame1.Draw見た目は次のようになっています。

spriteBatch.Begin();

base.Draw(gameTime); // draws elements of Game.Components

// ...

spriteBatch.End();

Q2 : このように、Begin一度だけ呼び出されます。これは行く方法ですか?皆さんはこれをどのように解決しましたか?


Q3 : また、すべてのコンポーネントには独自のIGameComponent.LoadContentメソッドがあります。そこにコンテンツをロードする必要がありますか? それとも、 などの親クラスでコンテンツをロードする方がよいGame1.LoadContentでしょうか?


同じコンテンツを 2 回ロードしてはならないことに気付いたので、ドローアブル コンポーネントに static と non-static の両方を指定Texture2Dし、2 つのコンストラクターを指定しました。

static Texture2D defaultTexture;
public Texture2D MyTexture;

public Enemy()
    : this(defaultTexture) { }

public Enemy(Texture2D texture)
{
    MyTexture = texture;
}

protected override void LoadContent()
{
    if (MyTexture == null)
    {
        if (defaultTexture == null)
        {
            defaultTexture = Content.Load<Texture2D>("enemy");
        }

        MyTexture = defaultTexture;
    }
}

LoadContentこのように、クラスのデフォルト テクスチャは、そのクラスで最初に呼び出されたときにのみロードされます。ただし、textureコンストラクターでパラメーターを指定する場合は、そのテクスチャーを事前にロードする必要があります。

Q4 : もっと良い方法があると思います。アセット名を文字列としてテクスチャ ディクショナリを作成することを考えています。何を提案しますか?

4

3 に答える 3

3

以前は Game1 の spriteBatch static を宣言していました

静的にする必要はありません。シングルトンを作るだけです。インサイドDraw

SpriteBatch spriteBatch = ScreenManager.SpriteBatch; // singletion SpriteBatch
spriteBatch.Begin();
// Draw the background
spriteBatch.Draw(background, ...
foreach (var enemy in enemys)
{
     enemy.Draw(gameTime);
}
// etc.
spriteBatch.End(); // call here end 
base.Draw(gameTime); // and then call the base class

SpriteBatch インスタンスを 1 つ持ち、begin/close を 1 回だけ呼び出すのが最善だと思います。これは正しいです?

SpriteBatch1 つのメソッド内で開始して終了することをお勧めします。SpriteBatch描画を開始したが終了していないという競合を回避するのに役立ちます。

コンポーネントのグローバル コレクションに要素を追加していますか? これは、このコレクションにドローアブルを追加するのは悪い考えです。描画の順序を制御することはできません。コンポーネントはグローバルです。この回答を参照してください

コンポーネント IUpdatable および IDrawable に実装し、コード内の必要な場所でそれらを呼び出します。静的なものを取り除き、代わりに依存性注入を使用してください。

また、すべてのコンポーネントには独自の IGameComponent.LoadContent メソッドがあります。そこにコンテンツをロードする必要がありますか? それとも、Game1.LoadContent などの親クラスでコンテンツをロードする方がよいでしょうか?

必要なときにアセットをロードする必要があり、責任を負います。ユーザーがゲームを開始したばかりのときに、30 レベルすべてをロードする必要はありませんね。たとえば、ゲームの開始時に、開始画面とメイン メニューに必要なすべてのアセットを読み込みます。必要なものだけをロードすると、プレイヤーはゲームの開始が速いことに満足します。次に、プレーヤーはゲームプレイを開始したいと考えています。ここでは、アセットを別のスレッドにロードして、アプリの応答性を維持できます。

これを行うためのより良い方法があるはずだと思います。アセット名を文字列としてテクスチャ ディクショナリを作成することを考えています。何を提案しますか?

Content.Loadすでにキャッシュされているので、それを行う必要はありません。

于 2012-12-20T11:15:30.510 に答える
1

周りのチュートリアル から収集できる限り

begin と end を 1 回だけ呼び出すことをお勧めします。

于 2012-12-20T11:12:33.673 に答える
0

Q4 : もっと良い方法があると思います。アセット名を文字列としてテクスチャ ディクショナリを作成することを考えています。何を提案しますか?


A4 : 私は通常、実行時に png 画像の読み込みを処理するクラスDictionary<string, Texture2D> NameTextureDic内にを作成するTextureLibので、次のように任意のテクスチャを取得できます。

var t2d = textureLib.NameTextureDic["tree-4"];
于 2012-12-21T09:45:41.153 に答える