XNA メモ – 振動エフェクトの作り方

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

このメモでは爆発や、強烈な攻撃などの衝撃の際に、画面が振動して見えるエフェクトの作り方を紹介します。

 

上記の説明だけではわかりにくいので、まずは以下の画像をご覧ください:

通常のゲーム画面

振動エフェクト中のゲーム画面

 

振動のエフェクトは上にある2番目の画像の用に始まり、徐々に薄くなって最終的には元に戻るようになります。

 

では実装に入ります。まず、エフェクトで振動の為に実際に使われる数値などを保存するクラスを作ります。

 

class Blast
{
public float Amount;    // 量
public float Megnitude; // 震度
public Vector2 Center;  // 中心点

 

今回実装するクラスは、簡易化のため、基本的にメンバ変数はpublicにしています。次に、更新処理です。ここでは、徐々に振動を減らすための計算に使用されるAmountメンバ変数を徐々に下げていきます。

 

public void Update(float delta)
{
if (Amount >= 0.0f)
{
Amount -= delta;
}
else if (Amount < 0.0f)
{
Amount = 0.0f;
}
}

 

これでBlastクラスの実装は終わりです。次に、Blastクラスを使用して実際にエフェクトを作製し、描画するクラスを宣言します。

 

static class ShakeManager
{
public static Blast Blast = new Blast();
public static int ShakeStrength = 4;     // エフェクトの濃さ

 

このクラスも、使用しやすいようにstaticクラスにしています。ですが、staticクラスでなくてはいけないということは無いので、staticを外して実装しても問題は無いです。

 

次は、更新処理を実装します。今回は、BlastクラスのUpdate()メソッドを呼ぶだけです。

 

public static void Update(float delta)
{
Blast.Update(delta);
}

 

次に、Blastクラスの値を設定するメソッドを実装します。このメソッドは衝撃のエフェクトを使用し始めたい時に呼びます。

 

public static void SetupBlast(float magnitude, Vector2 center)
{
Blast.Amount    = magnitude;
Blast.Megnitude = magnitude;
Blast.Center    = center;
}

 

今度は描画処理を実装します。振動のエフェクトもこのメソッド内で計算され、描画されます。

 

描画処理のメソッドには、引数の一つとして、ゲーム画面を保存しているテクスチャアを送る必要があります。エフェクトを作製する際、送られてきた画像を元に手を加える事で振動のエフェクトを実装しているので、描画の度に最新のゲーム画面を送る必要があります。

 

public static void Draw(SpriteBatch sp, Texture2D gameContent)
{
if (Blast.Amount > 0.0f)
{
// 設定されている震度の濃さの分だけエフェクトを描画する
for (int i = 0; i < ShakeStrength; i++)
{
// 原点を計算する
Vector2 origin = ShakeManager.Blast.Center / 2;

// 描画位置を計算する
Vector2 pos = Blast.Center - origin;

// アルファ値を計算する
float alpha = 0.35f * (Blast.Amount / Blast.Megnitude);
Color col = new Color(1.0f, 1.0f, 1.0f, alpha);

// 大きさを計算する
float scale = (1.0f + (Blast.Megnitude - Blast.Amount) *
               0.1f + ((float)(i + 1) / 40.0f));

// エフェクトを描画する
sp.Draw(gameContent, pos, null, col, 0.0f,
origin, scale, SpriteEffects.None, 1.0f);
}
}
}

このエフェクトの実装には、実際に弄ってみてよく見える数値を探し、そのまま使用している為、数値がそのまま入っている部分が多くなっています。

 

エフェクトの実装は終了したので、後は実際に使うだけです。まず、エフェクトの初期化をします。第2引数に入れた数値は、サンプルでの画面の中心点です。

 

ShakeManager.SetupBlast(1.5f, new Vector2(400, 300));

 

次に更新処理を呼びます。

 

public override void Update(GameTime gameTime)
{
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
ShakeManager.Update(delta);
base.Update(gameTime);
}

 

そして描画時に実際に使用してみます。

 

</pre>
public override void Draw(GameTime gameTime)
{
GraphicsDevice.SetRenderTarget(0, m_renderTarget);
GraphicsDevice.Clear(Color.Black);

// ゲーム画面をテクスチャアに描画する
DrawContent(gameTime);

GraphicsDevice.SetRenderTarget(0, null);
spriteBatch.Begin();


// ゲーム画面を描画する
spriteBatch.Draw(m_renderTarget, Vector2.Zero, Color.White);

// エフェクトを描画する
ShakeManager.Draw(spriteBatch, m_renderTarget);
spriteBatch.End();
}

 

以上です。これで、最初に紹介した画像の様なエフェクトが描画されます。エフェクトの見かけは、振動の初期価値と、ShakeManager.ShakeStrengthの値を変更すると結構変わるので、試してみてください。

 

コメント
  1. MonoGameでこのエフェクトを再現させていただこうと思っているのですが、DrawContentなるメソッドが何者なのかわかりません、、、
    教えていただけないでしょうか

    • K1 より:

      DrawContent()は実際に画面に描画したいもの纏めたメソッドの省略として入れてるので、中で背景やキャラを通常のSpriteBatch.Draw()で呼んでいるだけになります。

コメントを残す