DrawableGameComponent

Siden oppdatert :
ページ作成日 :

前回、GameComponent について説明しましたが、あれは更新用のみのクラスでした。実は同じように描画用のコンポーネントも作成することが可能です。それが「DrawableGameComponent」です。

DrawableGameComponent は GameComponent クラスと IDrawable インターフェースを継承して描画メソッドをオーバーライドできるように追加されています。

このクラスはテンプレートには用意されていないので自分で作成する必要があります。


今回のサンプル

Character コンポーネントを作成してスプライトを描画しています。操作は出来ません。

Character コンポーネントで描画


Character コンポーネントクラスを作成する

LoadGraphicsContent メソッドと Draw メソッドをオーバーライドしているところ以外は今までとほとんど同じなので、ざっと眺めてください。

後、コンストラクタには Game クラスではなく GameMain クラスを渡すようにしています。

Character.cs

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace UseDrawableGameComponent
{
    /// <summary>
    /// キャラクタークラス
    /// </summary>
    public partial class Character : Microsoft.Xna.Framework.DrawableGameComponent
    {
        /// <summary>
        /// コンテンツ管理クラス
        /// </summary>
        GameMain game = null;

        /// <summary>
        /// スプライトバッチ
        /// </summary>
        SpriteBatch sprite = null;

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


        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="game">ゲームクラス</param>
        public Character(GameMain game)
            : base(game)
        {
            this.game = game;
        }


        /// <summary>
        /// 初期化処理
        /// </summary>
        public override void Initialize()
        {
            // TODO: ここに初期化処理を追加します

            base.Initialize();
        }

        /// <summary>
        /// グラフィクスコンテンツの読み込み処理を行う
        /// </summary>
        /// <param name="loadAllContent">全コンテンツ読み込みフラグ</param>
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                // TODO: 自動管理リソースの読み込みをここに書きます

                // スプライトバッチ作成
                this.sprite = new SpriteBatch(this.game.Graphics.GraphicsDevice);

                // スプライト用テクスチャーの読み込み
                this.texture = this.game.Content.Load<Texture2D>("Wankuma");
            }

            // TODO: 手動管理リソースの読み込みをここに書きます

            base.LoadGraphicsContent(loadAllContent);
        }


        /// <summary>
        /// 更新処理
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれた時点でのゲーム時間</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: ここに更新処理を記述します

            base.Update(gameTime);
        }

        /// <summary>
        /// 描画処理
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれた時点でのゲーム時間</param>
        public override void Draw(GameTime gameTime)
        {
            // スプライトの描画は「Begin」「End」の間に記述する
            this.sprite.Begin();

            // スプライトの描画
            this.sprite.Draw(this.texture, new Vector2(200.0f200.0f), null, Color.White,
                0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0.0f);

            this.sprite.End();

            base.Draw(gameTime);
        }
    }
}

GameMain クラス

フィールドをコンポーネントで呼べるようにプロパティ化したのと、Game コンストラクタを以下のようにした点以外は手を付けていません。これもコンポーネントクラスを使用していることによって LoadGraphicsContent メソッドと Draw メソッドがコンポーネント側で自動で呼ばれるからです。

/// <summary>
/// グラフィクスデバイス管理クラス
/// </summary>
GraphicsDeviceManager graphics = null;
/// <summary>
/// グラフィクスデバイス管理クラス
/// </summary>
public GraphicsDeviceManager Graphics
{
    get { return this.graphics; }
}

/// <summary>
/// コンテンツ管理クラス
/// </summary>
ContentManager content = null;
/// <summary>
/// コンテンツ管理クラス
/// </summary>
public ContentManager Content
{
    get { return this.content; }
}


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

    // コンテンツ管理クラスの作成
    content = new ContentManager(Services);

    // タイトルバーのテキスト
    this.Window.Title = "DrawableGameComponent";

    // ウインドウ上にマウスカーソルを表示する
    this.IsMouseVisible = true;

    // ゲームクラスのコンポーネントに追加
    this.Components.Add(new Character(this));
}

一応ざっとコードを書いてきましたが、コンポーネントとしてはあまり好ましい書き方ではないと思います。なぜならコンポーネントが GameMain クラスに依存してしまっているからです。

それよりもなによりも、Direct3D では描画順というものが大きく関わっているので、今回のように1体だけを描画するのであれば問題ないのですが、複数になった場合、スプライトをまとめるクラスなどを作って SpriteBatch を効率よく使えるように工夫しなくてはいけません。

特に3Dオブジェクトなんかになると「透明」「不透明」によっても描画順が変わるので、「DrawOrder」プロパティを使用して制御しなければいけないと思います。

このように、描画が関わってくるといろいろ面倒なことが多くなってくるので、よく考えた上でクラス構築をしていく必要があると思います。