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