XNAメモ:2Dゲーム用のカメラの作り方

Posted: 2012年1月5日 カテゴリー: プログラミングメモ, XNA, XNAメモ
タグ:, , , , , , , ,

今回は2Dゲーム専用のカメラの作り方を紹介します。

 

まず、カメラに必要なメンバを宣言します。今回使うのは、カメラの位置、画面の中心点、ズーム値、カメラがどの位回転しているかを表す値、そして見える範囲です。

 

public class Camera2D
{
Vector2 m_position = Vector2.Zero;
Vector2 m_zoom = Vector2.One;
Rectangle m_visibleArea;
float m_rotation = 0.0f;
Vector2 m_screenPosition = Vector2.Zero;

 

次は、コンストラクタ内で初期化です。引数のwidthとheightは描画領域の大きさです(画面全体の場合は画面の横幅と、縦幅)。

 

public Camera2D(int width, int height)
{
m_visibleArea = new Rectangle(0, 0, width, height);
m_position = new Vector2(width / 2, height / 2);
Position = m_position;
m_screenPosition = new Vector2(width / 2, height / 2);
        }

 

初期化の後は、カメラの位置の移動処理です。まず、位置情報のアクセサは、set時に位置の変更だけでなく、見える範囲の変更も同時にしています。後は、メソッドを作る必要性は無いですが、移動する量を渡して移動するメソッドを作りました。

 

public Vector2 Position
{
get { return m_position; }
set
{
m_position = value;
m_visibleArea.X = (int)(m_position.X - m_visibleArea.Width / 2);
m_visibleArea.Y = (int)(m_position.Y - m_visibleArea.Height / 2);
}
}

public void Move(float x, float y)
{
Position = new Vector2(m_position.X + x, m_position.Y + y);
}

 

最後に、実際にカメラを使っての描画方法です。描画の時には、カメラの持つ情報から行列を作製し、spritebatch.Begin()メソッドのパラメーターに渡します。これにより、spritebatch.End()メソッドが呼ばれるまでの間に行われたspritebatch.Draw()メソッドにはカメラの情報が適用されます。
行列の作製にはまず、位置と画面の中心点を2次元用のベクトルから、3次元用のベクトルに変更します。次に、カメラの持っている情報を組み合わせて行列を作ります。
組み合わせは、移動用行列(-カメラの位置)x スケーリング用の行列(ズーム) x 回転行列(角度) x移動用行列 (画面の中心地)です。最初に移動するのは、カメラの周りを回転したり、サイズ変更したりする為です。
行列同士の掛け算は、順番で結果が変わるので、この順番を守らないと、違う結果になります。ちなみに、3Dモデルとかの移動時にも計算する順番はスケーリング x 回転 x 移動になります。

 

public virtual Matrix GetMatrix()
{
Vector3 pos = new Vector3(m_position, 0);
Vector3 screenPos = new Vector3(m_screenPosition, 0.0f);

return Matrix.CreateTranslation(-pos) *
Matrix.CreateScale(m_zoom.X, m_zoom.Y, 1.0f) *
Matrix.CreateRotationZ(m_rotation) *
Matrix.CreateTranslation(screenPos);
}

 

後はカメラのインスタンスを作り、spritebatch.Begin()を使うときに行列を作るだけです。

 

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

//ここの第4引数で、カメラの行列を渡す</pre>
<pre>spriteBatch.Begin(SpriteSortMode.Deferred,
                  BlendState.AlphaBlend,
                  SamplerState.LinearClamp,
                  DepthStencilState.None,
                  RasterizerState.CullCounterClockwise,
                  null,
                  camera.GetMatrix() );

// ...カメラ内の描画
spriteBatch.End();

spriteBatch.Begin();
// ...カメラ外の描画
spriteBatch.End();
}

 

このカメラクラスの使用例です。レベルエディタのゲーム場面の描画部分でカメラが使われています。

以上です。

 

コメント
  1. […] 今回はあまりのネタの無さに、昔別サイトの掲示板で書いた物を書き直して見ました。このメモは、前に書いた2Dカメラの作り方と同じ論理でC++とdirectx9で2D用のカメラの作り方を乗せます。ちなみに、今回は描画を全てID3DXSpriteを使用していますので、板ポリゴンを使用する場合は別の方法をとってください。 […]

  2. Lat より:

    毎度お世話になっております。早速ですがこの2Dゲーム用のカメラのソースをいただけないでしょうか。
    メールでもGitHubでも構いませんので、いただけると大変助かります。

    • K1 より:

      すみませんがHDDが死亡した時に埋もれたサンプルの一つなので、時間に余裕がある時まで用意出来ないと思います。

      記事に必要な情報は載っていると思うのですが、何処か解りにくい所があればご指摘ください m_ _m

      • Lat より:

        そうだったのですか、詳しい事情も知らずに厚かましいことを言って大変申し訳ありません。
        昨日PSMでこの2Dカメラのプログラムを使用してみたところ、
        「spriteBatch.Beginに引数を4つ指定することはできません」
        といわれ(私のプログラムが間違っているのかもしれません)、そこでK1様のプログラムが戴ければ私の間違いを見つけられるなと思ってコメントさせていただきました。

      • Lat より:

        追記で失礼します。
        調べてみたところ、どうやら
        spriteBatch.BeginはXNA3.1では引数を4つ指定できましたが、
        XNA4.0からは引数が7つのようです。
        http://azururu115.blog.fc2.com/blog-entry-77.html
        お騒がせしました。

      • K1 より:

        ご指摘ありがとうございます m_ _m。
        確かに処理が3.1のままになってました・・・orz
        一応記事の方も修正しておきました。

コメントを残す