神崎隼BLOG-ラスタースクロール

 今更、Xbox LIVE インディーズ ゲーム開始記念に、ラスタースクロールについて書いてみようのコーナー。

 ラスタースクロールが何かは、説明しなくてもわかると思うけど、画面がグニャグニャするアレ。
 まぁ、知らない人は、ググッて下さい。

 ラスタースクロールにも色々と種類があるようですが、今回は、所謂、横ラスターです。

 XNA でその効果を実装するには、レンダーターゲットにグニャグニャさせたい物を描画して、グニャグニャと描画すれば終わりです。(頭の悪過ぎる説明)

 説明するより、コードを見たり、実行してみたりするのが、早いと思うので、早速、実装方法をサクッと説明。
※アメブロでは半角スペース使えないため、インデントには全角スペースを使用しています。

 とりあえず、Platformer スターター キットに追加する形でするので、それで新規作成して下さい。

 で、まずは、描画用の変数を定義させます。場所はどこでも良いので、PlatformerGame のコンストラクタの手前にでも、以下の定義を放り込んで下さい。

  RenderTarget2D renderTarget;

  int roll = 12;
  int loopCount = 360;
  int count;

 renderTarget はグニャグニャさせる物を描く用で、roll はグニャグニャ度合いみたいに理解して下さい。
 loopCount は count の最大値で、count はカウンターです。loopCount を小さくすると、高速でグニャグニャします。

 さて、続いては変数の初期化。

 LoadContent 関数の中の最後に、次のコードを追加して下さい。

  renderTarget = new RenderTarget2D(GraphicsDevice, BackBufferWidth, BackBufferHeight, 1, SurfaceFormat.Color);

  count = 0;

 今回は、Platformer の通常の描画をラスタースクロールさせるので、バックバッファと同じサイズのレンダーターゲットを作成してます。
 実際に使用する場合は、用途に合わせて変更して下さい。

 初期化が終わって、次は更新処理。

 Update 関数の最後に、次のコードを追加して下さい。

  if (loopCount - 1 > count)
    count++;
  else
    count = 0;

 そして、最後は描画。

 勿論、コードを追加するのは、Draw 関数です。

 追加箇所は二箇所で面倒なので、コードを全て書いてしまいましょう。

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

    GraphicsDevice.SetRenderTarget(0, renderTarget);
    GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin();

    level.Draw(gameTime, spriteBatch);

    spriteBatch.End();

    GraphicsDevice.SetRenderTarget(0, null);

    spriteBatch.Begin();

    Texture2D tex = renderTarget.GetTexture();
    Vector2 vec = new Vector2();
    Rectangle rect = new Rectangle(0, 0, tex.Width, 1);

    for (vec.Y = 0; vec.Y < tex.Height; vec.Y += rect.Height)
    {
      vec.X = (float)((graphics.PreferredBackBufferWidth - tex.Width) / 2 + Math.Cos((count * 360 / loopCount + vec.Y) * MathHelper.Pi / 180) * roll);

      spriteBatch.Draw(tex, vec, rect, Color.White);

      rect.Y += rect.Height;
    }

    DrawHud();

    spriteBatch.End();

    base.Draw(gameTime);
  }

 肝は、for 文の中の一行目の計算ですかね? cos 関数でグニャグニャ位置を計算しています。

 それと、1ドットずつのラスターにしてますが、処理不可が気になる場合は、以下の行の最後の引数を増やして下さい。

  Rectangle rect = new Rectangle(0, 0, tex.Width, 1);

 この1を4にすると、for 文のぶん回し回数が1/4になります。勿論、4ドット単位でのスクロールになりますので、あまり大きくすると良くわからない効果になりますので、注意が必要です。

 どうでも良いですが、DrawHud 関数の呼び出しを level.Draw の後に移動させると、スコアとかもグニャグニャして少し楽しいです。

 さて、「ピクセルシェーダーでできそうな気もするけどやった事ないし、Zune でも動くと思うから」と言う事で、レンダーターゲットを使用した実装方法を紹介してみました。

 蛇足ですが、描画部分をちょっと変更すると縦ラスターにもなります。