使用 Layer 參數創建 Sprite 上下文

更新頁 :
頁面創建日期 :

總結

使用圖層的 depth 值來指定 Sprite 的上下文。

レイヤーパラメータを使用してスプライトの前後関係を作る

經營環境

先決條件

支援的 XNA 版本
  • 2.0
  • 3.0
  • 3.1
  • 4.0
支援的平臺
  • Windows(XP SP2 或更高版本、Vista、7)
  • Xbox 360 的
  • Windows Phone 7 系列
Windows 所需的頂點著色器版本 2.0
Windows 所需的像素著色器版本 2.0

經營環境

平臺
  • 視窗 7
  • Xbox 360 的
  • Windows Phone 7 模擬器

物質

通常,在繪製 sprite 時,會繪製該 sprite,以便稍後繪製的內容位於您面前,但通過按深度值排序,無論調用 SpriteBatch.Draw 方法的順序如何,都可以使上下文清晰。

若要按sprite depth值排序,請將“SpriteSortMode.BackToFront”指定為“SpriteBatch.Begin”方法的第一個參數。 這是一種從後面的sprite中提取並覆蓋前臺的sprite的處理方法。

// 一つでも半透明、透明要素があるスプライトの場合はこちらの引数を使用
this.spriteBatch.Begin(SpriteSortMode.BackToFront, null);

但是,如果您只想繪製半透明或根本沒有透明元素的sprite,則可以通過指定以下內容來更快地繪製它。

// 深度バッファを使用して前後関係を有効にし描画するように指定
// 完全な不透明スプライトのみ描画する場合はこちらが高速
this.spriteBatch.Begin(SpriteSortMode.FrontToBack,
                       BlendState.Opaque,
                       null,
                       DepthStencilState.Default,
                       null);

第四個參數是「DepthStencilState.Default」,它還會在繪製子畫面時將“深度”資訊寫入每個圖元。 寫入深度資訊時,可以確定該位置之後的要繪製的物件(以像素為單位)不需要寫入,因此繪製成本大大降低。

由於上述原因,如果先在前臺繪製 sprite,則重疊在其後面的 sprite 的繪製成本將降低,因此通過指定 “SpriteSortMode.FrontToBack” 作為從前臺繪製的第一個參數,對其進行排序,以便從前面繪製。

但是,這僅在繪製不透明 sprite 且其後面的顏色元素完全可以忽略不計時才有用。 對於半透明或不透明的 Sprite,即使它是半透明或透明圖元,深度值也會寫入每個圖元,因此如果您從前面繪製,則不會顯示您後面的 Sprite。 這就是在角色繪製中指定 「SpriteSortMode.BackToFront」 的原因。 (因為文字形狀以外的像素是透明的)

順便說一句,在我的環境中繪製 30,000 個 sprite 的測試結果顯示,使用深度值從前面繪製的速度大約比從後面繪製快 3 倍。 當然,這取決於要繪製的圖紙數量、重疊程度、大小等,以及執行環境,所以請自己嘗試一下。

SpriteBatch.Begin 方法

在繪製sprite之前調用它。 在內部,我們正在為繪製sprite進行必要的設置。

sortMode SpriteSortMode (精靈排序模式) 指定從SpriteSortMode枚舉中繪製sprite的順序。 如果要從背面繪製,請指定 SpriteSortMode.BackToFront。 如果要從前面繪製,請指定 SpriteSortMode.FrontToBack。
混合狀態 BlendState (混合狀態) 如何將要繪製的sprite的顏色與背景色混合。 默認情況下,指定了 BlendState.AlphaBlend,但在這種情況下,要繪製的 sprite 是完全不透明的,因此指定了 BlendState.Opaque,而不考慮背景色。
samplerState SamplerState (采樣狀態) 紋理的採樣方式。 如果指定了 null,則指定預設的 SamplerState.LinearClamp。
depthStencilState DepthStencilState 指定如何使用深度模具緩衝區。 如果指定了 null,則使用 DepthStencilState.None,它不使用深度模具緩衝區。 如果要使用深度模具緩衝區,請指定 DepthStencilState.Default。
rasterizerState RasterizerState 指定柵格化方法,如反向剔除。 如果指定了 null,則指定預設的 RasterizerState.CullCounterClockwise。

若要繪製 sprite,請將深度值指定為 SpriteBatch.Draw 方法的第九個參數。 此處可設置的值在0.0~1.0的範圍內,其中0.0是最前面的,1.0是最後面的。

// 最背面に描画(赤)
this.spriteBatch.Draw(this.texture, new Vector2(150.0f, 50.0f), null,
    Color.Red, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);

// 最前面に描画(緑)
this.spriteBatch.Draw(this.texture, new Vector2(110.0f, 90.0f), null,
    Color.Green, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);

// 2つのスプライトの間に描画(青)
this.spriteBatch.Draw(this.texture, new Vector2(190.0f, 130.0f), null,
    Color.Blue, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f);

SpriteBatch.Draw 方法

將 Sprite 新增到 Sprite 繪製批處理清單中。

質地 紋理2D 指定要顯示為 Sprite 的紋理。
位置 向量 2 sprite 應顯示的位置。 在螢幕座標中指定相對於螢幕左上角的座標。 精靈的原點將位於左上角位置。
sourceRectangle 的 Nullable<Rectangle 的 Nullable> 指定紋理的傳輸區域。 如果希望將整個紋理顯示為sprite,則可以指定 null。 如果指定此參數,則只能將任意區域顯示為Sprite。
顏色 顏色 指定顏色以乘以 Sprite 的顏色。 如果指定 Color.White,它將以 Sprite 的原色顯示。 如果指定了 Color.Black,則 sprite 將以全黑顯示,而不管其顏色如何。 公式為“結果 = sprite 顏色 * 顏色”。
旋轉 Sprite 的旋轉角度。 單位以弧度指定。 旋轉軸將位於sprite的左上角。
起源 向量 2 指定旋轉 Sprite 時旋轉軸的位置。 您可以指定Sprite的哪個位置是旋轉軸,但實際上,旋轉軸的位置固定在Sprite的左上角,並且Sprite的顯示位置由 -origin 移動。
規模 指定 Sprite 的放大倍數。 相對於 1.0 垂直和水平縮放。 放大的原點將位於Sprite的左上角。
影響 SpriteEffects (精靈效果) 指定 Sprite 的翻轉效果。 如果不執行任何其他操作,請指定SpriteEffects.None。
layerDepth 層深度 指定 Sprite 的顯示深度。 主要用於在前臺和後台顯示sprite。 在 0.0~1.0 的範圍內指定,其中 0.0 是前部,1.0 是後部。

在上面的程式中,SpriteBatch.Draw 方法是按照 “red”、“green” 和 “blue” 的順序調用的,但每個深度值都設置為“red (1.0)”、“green (0.0)”和“blue (0.5)”,所以你可以看到紅色在後面畫,綠色在前台畫。

深度値を使用したスプライトの描画

所有代碼

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif

namespace LayerDepthSprite
{
    /// <summary>
    /// ゲームメインクラス
    /// </summary>
    public class GameMain : Microsoft.Xna.Framework.Game
    {
        /// <summary>
        /// グラフィックデバイス管理クラス
        /// </summary>
        private GraphicsDeviceManager graphics = null;

        /// <summary>
        /// スプライトのバッチ化クラス
        /// </summary>
        private SpriteBatch spriteBatch = null;

        /// <summary>
        /// テクスチャー
        /// </summary>
        private Texture2D texture = null;


        /// <summary>
        /// GameMain コンストラクタ
        /// </summary>
        public GameMain()
        {
            // グラフィックデバイス管理クラスの作成
            this.graphics = new GraphicsDeviceManager(this);

            // ゲームコンテンツのルートディレクトリを設定
            this.Content.RootDirectory = "Content";

#if WINDOWS_PHONE
            // Windows Phone のデフォルトのフレームレートは 30 FPS
            this.TargetElapsedTime = TimeSpan.FromTicks(333333);

            // バックバッファサイズの設定
            this.graphics.PreferredBackBufferWidth = 480;
            this.graphics.PreferredBackBufferHeight = 800;

            // フルスクリーン表示
            this.graphics.IsFullScreen = true;
#endif
        }

        /// <summary>
        /// ゲームが始まる前の初期化処理を行うメソッド
        /// グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
        /// </summary>
        protected override void Initialize()
        {
            // TODO: ここに初期化ロジックを書いてください

            // コンポーネントの初期化などを行います
            base.Initialize();
        }

        /// <summary>
        /// ゲームが始まるときに一回だけ呼ばれ
        /// すべてのゲームコンテンツを読み込みます
        /// </summary>
        protected override void LoadContent()
        {
            // テクスチャーを描画するためのスプライトバッチクラスを作成します
            this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

            // テクスチャーをコンテンツパイプラインから読み込む
            this.texture = this.Content.Load<Texture2D>("Texture");
        }

        /// <summary>
        /// ゲームが終了するときに一回だけ呼ばれ
        /// すべてのゲームコンテンツをアンロードします
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: ContentManager で管理されていないコンテンツを
            //       ここでアンロードしてください
        }

        /// <summary>
        /// 描画以外のデータ更新等の処理を行うメソッド
        /// 主に入力処理、衝突判定などの物理計算、オーディオの再生など
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Update(GameTime gameTime)
        {
            // Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
            // ゲームを終了させます
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
            }

            // TODO: ここに更新処理を記述してください

            // 登録された GameComponent を更新する
            base.Update(gameTime);
        }

        /// <summary>
        /// 描画処理を行うメソッド
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Draw(GameTime gameTime)
        {
            // 画面を指定した色でクリアします
            this.GraphicsDevice.Clear(Color.CornflowerBlue);

            // 深度バッファを使用して前後関係を有効にし描画するように指定
            // 完全な不透明スプライトのみ描画する場合はこちらが高速
            this.spriteBatch.Begin(SpriteSortMode.FrontToBack,
                                   BlendState.Opaque,
                                   null,
                                   DepthStencilState.Default,
                                   null);

            // 一つでも半透明、透明要素があるスプライトの場合はこちらの引数を使用
            //this.spriteBatch.Begin(SpriteSortMode.BackToFront, null);

            // 最背面に描画(赤)
            this.spriteBatch.Draw(this.texture, new Vector2(150.0f, 50.0f), null,
                Color.Red, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);

            // 最前面に描画(緑)
            this.spriteBatch.Draw(this.texture, new Vector2(110.0f, 90.0f), null,
                Color.Green, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);

            // 2つのスプライトの間に描画(青)
            this.spriteBatch.Draw(this.texture, new Vector2(190.0f, 130.0f), null,
                Color.Blue, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f);

            // スプライトの一括描画
            this.spriteBatch.End();

            // 登録された DrawableGameComponent を描画する
            base.Draw(gameTime);
        }
    }
}