メディアプレイヤー内のアルバムに含まれる音楽データを使ったシューティングゲームを公開してみます。
このゲームではPC内のアルバムを使用するため音楽データは含まれていません。
また、セレクト画面でスペースキーを押すことでWeb上の音楽をURIで指定することができます。
※対応していないURIを指定するとゲームが終了したりタイトル画面へ戻ることがあります。
このゲームのテーマ:
音楽、シューティング、拡張性
メディアプレイヤー内のアルバムに含まれる音楽データを使ったシューティングゲームを公開してみます。
このゲームではPC内のアルバムを使用するため音楽データは含まれていません。
また、セレクト画面でスペースキーを押すことでWeb上の音楽をURIで指定することができます。
※対応していないURIを指定するとゲームが終了したりタイトル画面へ戻ることがあります。
このゲームのテーマ:
音楽、シューティング、拡張性
以前書いた「音楽のビジュアライゼーションデータを取得」をXNA4.0で行ったところ、そのままでは使用できなくなりました。
原因はWindowsPhoneではデータを取得できないので仕様が変更されたためだと思われます。
ビジュアライゼーションデータを取得するための設定
// ビジュアライゼーションデータの読み込みを有効
MediaPlayer.IsVisualizationEnabled = true;
データを取得する前にこのコードを追加することでXNA4.0でも使用可能となりました。
msdnでサンプルのリンクが切れていたのでダウンロードの方法を書いておきます。
「http://create.msdn.com/~」となっているものはリンクが切れているので、
「http://xbox.create.msdn.com/~」へ変更するとダウンロードできます。
情報:http://xbox.create.msdn.com/ja-JP/home/news/samplecodelinkerror
今回はXNAで効果音の再生と細かい設定について説明したいと思います。
再生する効果音にはwav形式のファイルを使用し、効果音の再生にはSoundEffectInstanceクラスを使用します。
SoundEffectInstanceクラスを使用することでループ再生やボリュームを調節することができます。
サンプルコード
フィールド変数
// 効果音を読み込む変数
SoundEffect soundEffect;
SoundEffectInstance soundEffectInstance;
効果音を読み込むためにSoundEffectクラスとSoundEffectInstanceクラスを宣言します。
LoadContent
// 効果音の読み込み
this.soundEffect = Content.Load<SoundEffect>(“効果音のアセット名”);
// SoundEffectの変換
this.soundEffectInstance = this.soundEffect.CreateInstance();
効果音の読み込みと変換を行います。
このとき、読み込む効果音が[サウンド エフェクト : XNA Framework]コンテンツプロセッサを使用している必要があります。
また、変換にはSoundEffect.CreateInstanceメソッドを使用します。
参考:SoundEffect.CreateInstance メソッド
効果音の再生
// ループ設定
this.soundEffectInstance.IsLooped = true;
// 効果音の再生
this.soundEffectInstance.Play();
効果音の再生にはSoundEffectInstance.Playメソッドを使用します。
ループ設定などは必ず効果音を再生する前に行ってください。
今回はXNAで効果音の再生について説明したいと思います。
再生する効果音にはwav形式のファイルを使用し、効果音の再生にはSoundEffectクラスを使用します。
サンプルコード
フィールド変数
// 効果音を読み込む変数
SoundEffect soundEffect;
効果音を読み込むためにSoundEffectクラスを宣言します。
LoadContent
// 効果音の読み込み
this.soundEffect = Content.Load<SoundEffect>(“効果音のアセット名”);
効果音の読み込みを行います。
このとき、読み込む効果音が[サウンド エフェクト : XNA Framework]コンテンツプロセッサを使用している必要があります。
効果音の再生
// 効果音の再生
this.soundEffect.Play();
効果音の再生にはSoundEffect.Playメソッドを使用します。
今回はXNAで複数のアニメーションをブレンドさせる方法について説明したいと思います。
このプログラムにはスキンアニメーションを使用します。
今回のアニメーションにはこの2つのアニメーションをブレンドさせます。
XNAサンプルコード
フィールド
// ボーンデータ
Matrix[] bones;
// アニメーションプレイヤー
AnimationPlayer animationPlayer1, animationPlayer2;
// ブレンド
float blend = 0.5f;
ボーンデータとアニメーションプレイヤー・補間値を作成します。
LoadContent
// アニメーションの読み込み
animationPlayer1 = new AnimationPlayer(skinningData);
AnimationClip clip1 = skinningData.AnimationClips[“move1”];
animationPlayer1.StartClip(clip1);
animationPlayer2 = new AnimationPlayer(skinningData);
AnimationClip clip2 = skinningData.AnimationClips[“move2”];
animationPlayer1.StartClip(clip2);
各アニメーションプレイヤーにアニメーションを読み込みます。
Update
// アニメーションプレイヤー
animationPlayer1.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);
animationPlayer2.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);
// ボーン
this.bones = animationPlayer1.GetSkinTransforms();
Matrix[] bones = animationPlayer2.GetSkinTransforms();
// アニメーションのブレンド
for (int i = 0; i < this.bones.Length; i++)
{
this.bones[i] = Matrix.Lerp(this.bones[i], bones[i], blend);
}
Matrix.Lrepメソッドを使用し、2つのボーンデータを補完します。
Draw
// モデルに含まれるメッシュの数だけ繰り返す
foreach (ModelMesh mesh in model.Meshes)
{
// エフェクトの数だけ繰り返す
foreach (Effect effect in mesh.Effects)
{
// ボーン情報をセット
effect.Parameters[“Bones”].SetValue(this.bones);
effect.Parameters[“View”].SetValue(view);
effect.Parameters[“Projection”].SetValue(projection);
}
mesh.Draw();
}
表示結果
2つのアニメーションを補間し、中間のアニメーションをブレンドさせました。
今回はXNAで環境マップを使用する方法について説明したいと思います。
環境マップとはスカイスフィアに使用する背景画像をモデルに反射しているように見せ、金属などのような質感を表現する方法です。
HLSLサンプルコード
フィールド
float Reflective = 0.25f; // 反射率 0から1
環境マップの反射率を指す変数Reflectiveを作成します。
// テクスチャーとサンプラー
texture EnvironmentMap;
sampler EnvironmentSmp = sampler_state
{
Texture = (EnvironmentMap);
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
背景画像用のテクスチャー変数とサンプラーを追加します。
// 頂点シェーダへ入力する情報
struct EnvironmentVSInput
{
float4 Position : POSITION0;
// UV座標
float2 TexCoord : TEXCOORD0;
// 法線
float3 Normal : NORMAL;
};
// 頂点シェーダから出力される情報
struct EnvironmentVSOutput
{
float4 Position : POSITION0;
// UV座標
float2 TexCoord : TEXCOORD0;
// 法線
float3 Normal : TEXCOORD1;
// 光方向
float3 Light : TEXCOORD2;
// 反射テクスチャー座標
float3 Reflection : TEXCOORD3;
};
頂点シェーダから出力される情報に反射テクスチャー座標を指す変数Reflectionを追加します。
// 頂点シェーダ
EnvironmentVSOutput EnvironmentVSFunction(EnvironmentVSInput input)
{
EnvironmentVSOutput output;
// ワールド座標の変換
float4 worldPosition = mul(input.Position, World );
// 視点座標の変換
float4 viewPosition = mul(worldPosition, View );
// 出力する座標の作成
output.Position = mul(viewPosition, Projection );
// 出力するUV座標の作成
output.TexCoord = input.TexCoord ;
// 出力する法線の作成
output.Normal = normalize(mul( input.Normal, World ));
// 出力する光方向の作成
output.Light = LightPosition.xyz – worldPosition.xyz;
float3 viewNormal = mul(output.Normal, View);
output.Reflection = reflect(normalize(viewPosition), viewNormal);
return output;
}
変換した視点座標と法線から反射テクスチャー座標を作成します。
// ピクセルシェーダ
float4 EnvironmentPSFunction(EnvironmentVSOutput input) : COLOR0
{
float3 N = normalize( input.Normal ); // 法線の正規化
float3 L = normalize( input.Light ); // 光方向の正規化
float3 diffuse = ( max( dot(N, L), 0.0f ) * 0.5f + 0.5f );
float4 output = float4( diffuse, 1.0f ) * tex2D( TextureSmp, input.TexCoord );
float3 envmap = texCUBE(EnvironmentSmp, input.Reflection);
output = float4( lerp(output, envmap, Reflective), output.w );
return output;
}
texCUBEを使用して背景画像から色情報を取得し、描画される色と合成します。
表示結果
今回はXNAでソフトパーティクルを使用する方法について説明したいと思います。
まず、ソフトパーティクルとは何か説明します。
ソフトパーティクルとはパーティクルに使用するモデルと背景となるモデルの境界部分をぼかし、エッジの発生を防ぐ技術です。
ソフトパーティクルにはシャドウマップのように深度情報を保存しておく必要があります。
深度情報の出力方法はシャドウマップ画像作成を参考にしてください。
ソフトパーティクルではシャドウマップと違い、光源からではなくカメラからの深度情報を使用します。
HLSLサンプルコード
フィールド
// フィールド変数
float4x4 World; // ワールド座標変換行列
float4x4 View; // 射影変換行列
float4x4 Projection; // 投影変換行列
float Offset = 1.0f;
必要な変数はシャドウマップとあまり変わりませんが、Offset変数の用途が変わります。
ソフトパーティクルではOffsetをどれだけの距離までを透過するか判定するために使用します。
// テクスチャーとサンプラー
texture Texture;
sampler TextureSmp = sampler_state
{
Texture = (Texture);
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
texture DepthMap;
sampler DepthSmp = sampler_state
{
Texture = <DepthMap>;
MagFilter = Linear;
MipFilter = None;
AddressU = Border;
AddressV = Border;
BorderColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
};
テクスチャーやサンプラーもシャドウマップとあまり変わりません。
// 頂点シェーダへ入力する情報
struct VertexShaderInput
{
float4 Position : POSITION0;
// UV座標
float2 TexCoord : TEXCOORD0;
};
// 頂点シェーダから出力される情報
struct VertexShaderOutput
{
float4 Position : POSITION0;
// UV座標
float2 TexCoord : TEXCOORD0;
// 深度
float4 Depth : TEXCOORD1;
};
パーティクルなので法線情報や光方向の情報は必要ありません。
// 頂点シェーダ
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World ); // ワールド座標の変換
float4 viewPosition = mul(worldPosition, View ); // 視点座標の変換
output.Position = mul(viewPosition, Projection ); // 出力する座標の作成
output.TexCoord = input.TexCoord; // 出力するUV座標の作成
output.Depth = output.Position; // 出力する深度情報の作成
return output;
}
// ピクセルシェーダ
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 output = tex2D( TextureSmp, input.TexCoord );
input.Depth.xy /= input.Depth.w;
float2 coord = input.Depth.xy * float2( 0.5f, -0.5f ) + 0.5f;
float depth = tex2D( DepthSmp, coord ).x;
float alpha = depth * input.Depth.w – input.Depth.z;
if ( alpha <= Offset )
{
alpha /= Offset;
output.w *= alpha;
}
return output;
}
頂点シェーダではシャドウマップ画像の出力と変わりませんが、ピクセルシェーダでは不透明度を計算する必要があります。
保存された深度とピクセルの深度の差がOffset以下か判定し、Offset以下の場合は差をOffsetで除算しテクスチャーの不透明度に乗算します。
表示結果
ソフトパーティクル適用前 |
ソフトパーティクル適用後 |
今回はXNAで画像ファイルの保存する方法について説明したいと思います。
画像の保存にはTexture.Saveメソッドを使用します。
ただし、XNA 4.0ではこのメソッドの代わりに以下のようなメソッドがあります。
Texture2D.SaveAsPng Method
Texture2D.SaveAsJpeg Method
サンプルコード
// テクスチャーの書き出し
texture.Save(“画像名.jpg”, ImageFileFormat.Jpg);
メソッドの引数には拡張子を含む書き出す画像の名前とファイルフォーマットを指定することでゲームと同じフォルダに保存されます。