4月, 2012 のアーカイブ

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

 

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

通常のゲーム画面

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

 

振動のエフェクトは上にある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の値を変更すると結構変わるので、試してみてください。

 

今回は、前回に引き続きHLSLを使って画面の色を反転する方法で紹介した処理を少しだけ変更し、違うエフェクトを作る方法を紹介します。

 

今回は前回実装したモノクロ処理に少しだけ処理を追加して、画面をセピア調に変更します。

 

まず、ピクセルの色を白黒からセピア調へ変更する際に使う色を.fxファイル内の上部に宣言します。

float4 sepiaTone = float4( 1.0f, 0.8f, 0.0f, 1.0f );  /ピクセルの調整値。

次に、ピクセルシェーダー内での処理で、前章同様白黒の色を計算し、その色に上記の色を掛けます。

float4 Sepia(PS_INPUT p) : COLOR0

{

// テクスチャアから現在の座標の色を獲得する

float4 col = tex2D( samplerState, p.TextureCoord.xy );

// 色を白黒化する

float tempPixel = ( col.r + col.g + col.b ) * 0.3333f;

//セピア調の色を計算する

col = tempPixel * sepiaTone;

return col;

}

これで後は、関数を呼ぶのを忘れないようにするだけです。

technique Flip

{

pass Pass0

{

PixelShader = compile ps_2_0 Sepia(); // Monotone, Negative()から変更

}

}

 

結構前のメモや、前回の物をそのまま使用した場合、これだけで動きます。

このメモでは、結構前のメモで紹介した色を反転させる処理を少しだけ変更し、画面の色を白黒に変える処理を紹介します。

 

このメモでの処理は、前回のコードを1行だけ変更すれば実装できるので、同じ説明でスペースと時間を無駄にしないため変更部分だけを解説します。なので、このメモを読む前に前のメモを読むことを強くオススメします。

 

では実装に入ります。前回の処理と違うのは、ピクセルシェーダー内で画面の色を変更する時の計算方法だけです。前回は[1 – colour.rgb]の式を使用して色を反転させましたが、今回はRGB値の平均を計算することで、白黒化した色を獲得できます。

 

.fxファイル内の、ピクセルシェーダーの関数は前章のから以下の用に変更されます。

float4 Monotone(PS_INPUT p) : COLOR0

{

// テクスチャアから現在の座標の色を獲得する

float4 col = tex2D( samplerState, p.TextureCoord.xy );

// 色を白黒化する

col.rgb = ( col.r + col.g + col.b ) * 0.3333f;

// 白黒の色を返す

return col;

}

これで後は、関数を呼ぶのを忘れないようにするだけです。

technique Flip

{

pass Pass0

{

PixelShader = compile ps_2_0 Monotone(); // Negative()から変更

}

}