WisdomSoft - for your serial experiences.

画像ファイルの読み込みと描画

画像ファイルからテクスチャを生成し、ゲーム画面にスプライトとして描画します。

スプライト

ここからは、いよいよゲーム画面に画像を表示するプログラムの書き方について説明します。XNA Framework の GraphicsDevice は 3 次元(3D)グラフィックスを前提としているため、Windows の GDI (Graphic Device Interface)  のようなピクセルベースの描画処理はサポートされていません。基本的には、複数の頂点を結んだポリゴンを 3D 空間上に配置し、これを複雑に組み合わせて立体的なオブジェクトを描画します。

しかし、2 次元(2D)のビットマップ画像を 描画する場合でも 3D 空間にポリゴンを作成して貼り付けるのは非効率的です。また、3DCG のゲームでも何らかのグラフや文字などの 2D 画像を画面の前面に表示させたいことがあります。このような 2D の画像を XNA Framework ではスプライトと呼びます。

スプライトは 3D ではなく、画面に直接描画されるビットマップです。スプライトの機能だけを使えば、2D だけのゲームを作成することも可能です。スプライトを描画するには Microsoft.Xna.Framework.Graphics.SpriteBatch クラスを使います。このクラスは、スプライトを描画する GraphicsDevice オブジェクトと関連付けられ、デバイスの設定やスプライとの描画を代行してくれます。

Microsoft.Xna.Framework.Graphics.SpriteBatch クラス
public class SpriteBatch : IDisposable

このクラスのコンストラクタには、スプライトを描画する GraphicsDevice オブジェクトを設定します。

SpriteBatch クラスのコンストラクタ
public SpriteBatch (GraphicsDevice graphicsDevice)

graphicsDevice パラメータに、スプライトを描画するグラフィックスデバイスを指定します。

通常、SpriteBatch オブジェクトは LoadContent() メソッドなどの初期化工程の中でインスタンス化し、フィールドに保持する形になります。必要なときに作成し、不要になって時点で解放するような短いサイクルで使っても問題はありませんが、Update() メソッドや Draw() メソッドの中でインスタンス化と破棄を繰り返すのは無意味な負荷です。

SpriteBatch オブジェクトを生成できれば、次にスプライトを描画する準備を行います。スプライトを描画するには、描画を行う前に Begin() メソッドを呼び出します。Begin() メソッドは、スプライトを描画するために  GraphicsDevice オブジェクトの設定を変更します。Begin() メソッドに対応する形で、描画処理が終了したら End() メソッドを呼び出さなければなりません。End() メソッドは、デバイスを Begin() メソッドが呼び出される前の状態に戻し、描画処理を終了します。

SpriteBatch クラス Begin() メソッド
public void Begin ()
SpriteBatch クラス End() メソッド
public void End ()

これらのメソッドは必ず対になって呼び出さなければなりません。描画を開始する前に Begin() メソッドを呼び出し、その後にスプライトの描画を行い、処理が終わった時点で End() メソッドを呼び出します。通常、この工程は Game クラスの Draw() メソッド内で行われます。

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.White);

    sprite.Begin();
    //スプライトの描画処理をここに記述します。
    sprite.End();

    base.Draw(gameTime);
}

スプライトを描画するには Begin() メソッドと End() メソッドの間で Draw() メソッドを呼び出します。

SpriteBatch クラス Draw() メソッド
public void Draw (Texture2D texture, Vector2 position, Color color)

texture パラメータにスプライトとして描画するテクスチャを指定します。position パラメータにはテクスチャを描画する座標を表す2次元ベクトルを、color パラメータには、描画するテクスチャと合成する色を指定します。テクスチャ本来の色で描画する場合は、完全な白色を表す Color.White を指定します。画像をグレー表示の状態とハイライトの状態に分けるなど、演出目的で画像の色を変調させるといった応用が可能です。

texture パラメータには、スプライトとして描画する Microsoft.Xna.Framework.Graphics.Texture2D クラスのオブジェクトを渡します。

Microsoft.Xna.Framework.Graphics.Texture2D クラス
public class Texture2D : Texture

このクラスは 2 次元のテクスチャを表します。3 次元グラフィックスでは、物体の表面に張り付ける画像のことをテクスチャと呼び、ポリゴンの表面にテクスチャを張り付けることで、岩肌や皮のような複雑な模様の質感を実現します。テクスチャは、画像の色を表す点を集めたものであり、一種のビットマップです。テクスチャが表す画像の点はテクセルとも呼ばれます。Texture2D クラスは、画像ファイルなどから読み込んだビットマップを 2 次元のテクセルの列として提供します。このとき、テクセルは元の画像のピクセルに対応します。

Texture2D をインスタンス化する方法はいくつかありますが、この場では Texture2D クラスの静的な FromStream() メソッドを使ってファイルから読み込む方法を用います。このメソッドを使うことで、画像ファイルを任意のストリームから直接読み込むことができます。 

Texture2D クラス FromStream() メソッド
public static Texture2D FromStream (
         GraphicsDevice graphicsDevice,
         Stream stream
)

graphicsDevice パラメータにはテクスチャの描画先となる GraphicsDevice オブジェクトを指定し、stream パラメータに画像データの読み込み元を指すストリームを指定します。このメソッドで読み込めるファイル形式は Windows ビットマップの他に、JPEG、PNG などの標準的な画像ファイルが含まれます。

コード1
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        using (Game game = new TestGame()) game.Run();
    }

    private GraphicsDeviceManager graphicsDeviceManager;
    private SpriteBatch sprite;
    private Texture2D texture;

    public TestGame()
    {
        graphicsDeviceManager = new GraphicsDeviceManager(this);
    }

    protected override void LoadContent()
    {
        sprite = new SpriteBatch(GraphicsDevice);

        using (FileStream stream = new FileStream("TestImage.png", FileMode.Open))
        {
            texture = Texture2D.FromStream(GraphicsDevice, stream);
        }
        base.LoadContent();
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.White);

        sprite.Begin();
        sprite.Draw(texture, Vector2.Zero, Color.White);
        sprite.End();

        base.Draw(gameTime);
    }
}
実行結果
コード1 実行結果

コード1は、ゲームの実行ファイルが配置されているフォルダにある "TestImage.png" という画像ファイルをテクスチャとして読み込み、ゲーム画面に描画するプログラムです。SpriteBatch や Texture2D の取得には GraphicsDevice オブジェクトが必要になるため、LoadContent() メソッド内でインスタンス化しています。また、UnloadContent() メソッドが呼び出されるタイミングで Dispose() メソッドを呼び出して明示的に破棄しています。

色の変調

Draw() メソッドの第 3 パラメータに完全な白以外の色を渡すと、テクスチャと合成されます。スプライトをフェードアウトさせるなど、画面効果として応用できます。

色の合成は、Draw() メソッドのパラメータに指定した色の各要素の比率と、テクスチャの色が乗算された結果となります。指定された色の要素が最も強い状態を 1.0 とし、空の状態を 0.0 とします。ARGB のカラーフォーマットにおいて、完全な白色は全ての要素が最大値となります。よって、テクスチャの元の色と 1 が乗算され、結果はテクスチャの色となります。逆に、完全な黒を渡すとテクスチャの色と 0 が乗算され、結果は完全な黒となってしまいます。

コード2
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        using (Game game = new TestGame()) game.Run();
    }

    private GraphicsDeviceManager graphicsDeviceManager;
    private SpriteBatch sprite;
    private Texture2D texture;

    public TestGame()
    {
        graphicsDeviceManager = new GraphicsDeviceManager(this);
    }

    protected override void LoadContent()
    {
        sprite = new SpriteBatch(GraphicsDevice);

        using (FileStream stream = new FileStream("TestImage.png", FileMode.Open))
        {
            texture = Texture2D.FromStream(GraphicsDevice, stream);
        }
        base.LoadContent();
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.White);

        sprite.Begin();
        sprite.Draw(texture, Vector2.Zero, new Color(85, 85, 85));
        sprite.Draw(texture, new Vector2(150, 50), new Color(170, 170, 170));
        sprite.Draw(texture, new Vector2(300, 100), Color.White);
        sprite.End();

        base.Draw(gameTime);
    }
}
実行結果
コード2 実行結果

コード2では、Draw() メソッドの color パラメータに白以外の色を渡しています。実行結果を見れば、テクスチャの本来の色と指定した Color オブジェクトの色が合成されることを確認できます。