前回、GameComponent について説明しましたが、あれは更新用のみのクラスでした。実は同じように描画用のコンポーネントも作成することが可能です。それが「DrawableGameComponent」です。
DrawableGameComponent は GameComponent クラスと IDrawable インターフェースを継承して描画メソッドをオーバーライドできるように追加されています。
このクラスはテンプレートには用意されていないので自分で作成する必要があります。
● 今回のサンプル
Character コンポーネントを作成してスプライトを描画しています。操作は出来ません。
● Character コンポーネントクラスを作成する
LoadGraphicsContent メソッドと Draw メソッドをオーバーライドしているところ以外は今までとほとんど同じなので、ざっと眺めてください。
後、コンストラクタには Game クラスではなく GameMain クラスを渡すようにしています。
#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.0f, 200.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」プロパティを使用して制御しなければいけないと思います。
このように、描画が関わってくるといろいろ面倒なことが多くなってくるので、よく考えた上でクラス構築をしていく必要があると思います。