忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

かんたんXNA その12 Game.Initializeメソッド

このページは古いです
最新版はこちら

小さなサンプルではその有効性はさっぱりわかりませんが、
大きなプログラムではGame.Initializeメソッドが
(グラフィックスで無い)データの初期化を分離するのに役に立ちます。
(これはちょうどjavaアプレットのinitメソッドのようなものです)

例えば座標データをこの中で初期化することが出来ます。

 


 

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


public class MyGame : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    VertexPositionColor[] vertices = new VertexPositionColor[3];
    VertexBuffer vertexBuffer;

    public MyGame()
    {
        graphics = new GraphicsDeviceManager(this);
    }

    protected override void Initialize()
    {
        vertices[0] = new VertexPositionColor(new Vector3(1, 0, 0), Color.White);
        vertices[1] = new VertexPositionColor(new Vector3(-1, 0, 0), Color.Red);
        vertices[2] = new VertexPositionColor(new Vector3(0, 1, 0), Color.Navy);

        base.Initialize();
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = new BasicEffect(graphics.GraphicsDevice, null);
            effect.VertexColorEnabled = true;
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),
                Window.ClientBounds.Width / (float)Window.ClientBounds.Height,
                1,
                100
                );
            effect.View = Matrix.CreateLookAt(
                new Vector3(0, 0, 3),
                new Vector3(0, 0, 0),
                new Vector3(0, 1, 0)
            );

            vertexBuffer = new VertexBuffer(
                graphics.GraphicsDevice,
                VertexPositionColor.SizeInBytes * vertices.Length,
                ResourceUsage.None
                );
            vertexBuffer.SetData<VertexPositionColor>(vertices);
        }
    }

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

        graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
            graphics.GraphicsDevice,
            VertexPositionColor.VertexElements
            );

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.Vertices[0].SetSource(
                vertexBuffer,
                0,  //The starting offset.
                VertexPositionColor.SizeInBytes
                );
            graphics.GraphicsDevice.DrawPrimitives(
                PrimitiveType.TriangleList,
                0,  //startVertex
                1   //primitiveCount
                );

            pass.End();
        }

        effect.End();
    }
}


xnaVertexBuffer.JPG(※前回と見た目は全く変わりません。)

ここでは今までコンストラクタ内で初期化していた
三角形の頂点データをMyGame.Initializeメソッド内で
初期化しています。

そのあとbase.InitializeでGame.Initializeメソッドを呼んでいます。

不可解です
なぜスーパークラスのInitializeメソッドを呼ばなければならないのでしょう?
その理由はもちろんWindowsFormsのControl.OnPaintメソッドの
オーバーライドでスーパークラスのOnPaintメソッドを
呼んでやらなければならない理由と同じです。
つまり、Game.Initializeメソッドが何か大切なことをしているからです。

このケースでは、Game.InitializeメソッドはLoadGraphicsContentメソッドを呼んでおり、
base.Initialize
を忘れるとグラフィックス関係のオブジェクトが全て初期化されずにnullのままで、
描画すると同時に例外(NullReferenceException)が飛びます。
(同様に、DrawメソッドとUpdateメソッドも本当はスーパークラスの
メソッドを呼んでやらなければなりません。
しかしGameComponentを使わない限りは大して問題はないですし
これはサンプルなので割愛しました。
実際に問題が出る時に対処しても遅くは無いでしょう。
YAGNIの原則です。)


これはまぁいいでしょう。
しかしなぜ一番最後にbase.Initializeを呼んでいるのでしょうか?

コンストラクタは普通基底クラスのものから先に呼ばれます。
派生して出来たクラスのコンストラクタで基底クラスの何かを
利用するときに困らないようになっているのです。
とすると同じ初期化を表すInitializeメソッドも一番最初に
base.Initializeを呼ぶべきであるようにも思えます。
一番最後に呼ぶのではまるでデストラクタです。

また、WindowsFormsのControl.OnPaintメソッドも、
普通は基底クラスのOnPaintメソッドを一番最初に呼びます。

この2つのケースを考えると、一番最後にbase.Initializeとするのは
気持ち悪いように思えます。
なぜ一番最後に呼ぶのでしょう?

まず一番最初に呼ぶとどうなるかを実際に見るのがいいかもしれません。
xnaSimplestTriangleWithCameraRotating4.JPG
・・・何も表示されません。
どうなっているのでしょう?

実はこれは一つ目の疑問と関係しています。
Game.InitializeメソッドはLoadGraphicsContentを呼んでいるので、
一番最初にGame.Initializeメソッドを呼ぶと
まだ三角形の頂点データが初期化されていないまま
VertexBufferが初期化されてしまうのです。

したがってVertexBufferの中はカラッポ。
何も表示されないというわけです。
 

拍手[0回]

PR