XNAコンポーネントのZ-indexを行うクールな方法は?


7

ゲームの一部の要素をレンダリングしようとしています。まず、テクスチャ(テキストボックス自体のテクスチャなど)をレンダリングします。次に、プリミティブ(コントロールの周囲の境界線など)をレンダリングします。次に、テキストをレンダリングします。

ただし、そうすることで、以下のスクリーンショットに示すように、(テキストフィールドにカーソルを合わせることによって)ツールチップを表示すると、ユーザーインターフェイスに奇妙な結果が生じます。

スクリーンショット

描画の順序が原因で、ウィンドウの周囲の境界線はテクスチャの後に描画されます。これにより(マウスがテキストフィールド上にあるときに表示されるツールチップの場合)、奇妙に見えます。

回答:


6

これらがそれぞれ別個のDrawableGameComponents場合はDrawOrder、各コンポーネントのプロパティを設定して、正しい順序で描画されるようにする必要があります。

コンポーネントを追加するときに管理しやすくするにDrawOrderは、をにする必要がありenumます。

/* DisplayLayer.cs */
public enum DisplayLayer
{
    Background, //back-layer
    Particles,
    Player,
    MenuBack,
    MenuFront //front-layer
}

public class MyComponent : DrawableGameComponent
{
    public MyComponent(Game game) : base(game)
    {
        this.DrawOrder = (int)DisplayLayer.Background;
    }

    /* etc. */
}

これがすべて1つの内に描画されているDrawableGameComponent場合は、@ Andrewのアドバイスに従って、単に正しい順序で描画する必要があります。なんらかの理由でそれができない場合でもenum、使用layerDepthするときにの値をenum0〜1に正規化するだけでsを明確にすることができます。

/* DisplayLayer.cs */
public enum DisplayLayer
{
    MenuFront, //front-layer
    MenuBack,
    Player,
    Particles,
    Background, //back-layer
    MAX_LAYER   //Do not use this as a layer
}

public void Draw()
{
    spriteBatch.Begin(SpriteSortMode.BackToFront);
    foreach(Thingy thingy in thingys)
        spriteBatch.Draw(/* blah blah */, (float)thingy.DisplayLayer/(float)DisplayLayer.MAX_LAYER);
    spriteBatch.End();
}

(バックレイヤーではなくフロントレイヤーに低い数値を使用するenumため、の順序は逆になりlayerDepthます)


6

http://msdn.microsoft.com/en-us/library/ff433989.aspx

public void Draw (
         Texture2D texture,
         Vector2 position,
         Nullable<Rectangle> sourceRectangle,
         Color color,
         float rotation,
         Vector2 origin,
         Vector2 scale,
         SpriteEffects effects,
         float layerDepth
)


layerDepthレイヤー の深さ。デフォルトでは、0はフロントレイヤーを表し、1はバックレイヤーを表します。描画中にスプライトをソートする場合は、SpriteSortModeを使用します。
たとえば、フォーム、フォームラベル、ボタンの
ように、子要素の場合は、layerDepthにいくつかの値を追加できます
例:フォームAには子があります:フォームBといくつかのボタン、フォームBにはボタンのみがあります
フォームA-1.0
ボタンフォームA-1.5
フォームBのフォームフォームBの
ボタン-2

ダイアログの場合-より大きな値を保存できます


4
この方法のいくつかの注意点:(layerDepth私はかなり確信している)の有効範囲は0〜1なので、その範囲内に留まる必要があります。さらに、すべての描画は(間に1つのスプライトバッチ内で行われる必要がありますBeginEnd)。最後に、この方法では、最初から正しい順序で単純に描画するよりもパフォーマンス上の利点がないことに注意してください。
Andrew Russell

6

私は単純でかなり明白な答えを与えるつもりです、そしてそれはただ最初にすべてを正しい順序で描くだけですです。

私の意味の例をモックアップするには:

// Assuming you have sorted windowList by Z-order, using one of the many
// existing sorting mechanisms provided by the framework such as List<T>.Sort().
foreach(var window in windowList)
    window.Draw();

// in your Window class:
public void Draw()
{
    this.DrawBackground();
    this.DrawBorders();
    this.DrawText();
}

この方法でウィンドウを描画していない特別な説得力のある理由はありますか?


彼が質問で述べているように、彼はSpriteBatchとプリミティブの両方の呼び出しを行っているため、それらを一緒にバッチ処理したいのではないかと思いますが、これは実際に悪い考えではありません。それでも、SpriteBatchはすべての呼び出しをバッチ処理するので、ツアーオプションは同じパフォーマンスであると確信しています。それはまたより理にかなっています。
ジョナサンコネル

@ 3nixios彼の理由もパフォーマンスにあると思いますが、それでは早すぎる最適化であることをすぐに示唆します。彼のGUIは本当にそれほどうまく機能していませんか?そして、バッチの統合は本当に最適化の正しい選択なのでしょうか?またSpriteBatch、テクスチャの変更をバッチ処理することはできません。そのため、彼の実装が適切に最適化されている場合、私の方法は彼の方法よりも遅くなる可能性があります。
Andrew Russell

そして、彼の方法は実行可能です-ところで。しかし、正しく実装することは困難です。これを適切な回答に変換することも含まれます。したがって、小さなパフォーマンスの向上にはおそらく努力する価値はありません。したがって、これは間違った答えになります。(ショートバージョンは、Zバッファーを使用します。)
Andrew Russell

私は完全に同意します:)
ジョナサン・コネル2011年

上記のアプローチでは、すべてのSpriteBatch操作をまとめてバッチ処理できないのはなぜですか。SpriteBatchパラメータを受け入れるように描画メソッドを変更するだけです。次に、最も基本的な「Draw」メソッドで、最初に呼び出しますSpriteBatch.Begin()-次にWindowsで「Draw」を呼び出します(渡してSpriteBatch、子が使用し、各子に渡します)-次に、ループの後、最も基本的な「Draw」メソッド、を呼び出しますSpriteBatch.End()。。。(私の$ 0.02:彼はオブジェクトを使用していないと思いますが、すべてがおそらく彼のメインGameクラスの大きな手続き上の混乱です。)
BrainSlugs83 '28
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.