

今後、力をいれていきます。

PSMゲーム
Bloodred Wyvern (ブラッドレッドワイバーン)
Bloodred Wyvern 2
Gravity Anomaly Zone 不可思議重力帯
その他
PlayStation®Mobile関連リンク集
PlayStation®Mobile学習日記

XBLIG
BLASTER AND AMETHYST
BLASTER AND MORION
LEUCISTIC WYVERN
Bioerosion
URGENT EVASION 360
The Undead Syndrome / TUS 2
Dark Storm Blast 360
その他
Making Of The Undead Syndrome[3DCG]
Making Of The Undead Syndrome2
XNA関連リンク集
xna学習日記
第1〜3話
第4〜5話
第6〜7話
第8〜9話
第10〜12話
第13〜14話
第15話

ブラウザゲーム
発火少年の地面焦がし
MAGICAL METEOR SHOWER

メタセコイア備忘録
東日本大震災(Aftermath of the 2011 Tohoku earthquake and tsunami)

ムカゴソフトウェア開発
e-mail:cqp00202@nifty.ne.jp
前回のサンプルコードに、ゲームパッドで立体モデルを動かすコードを追加してみた。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace WindowsGame1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Model samplemodel;
Vector3 model_pos = Vector3.Zero; //立体モデルの位置
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//モデルの読み込み
samplemodel = Content.Load<Model>("sample_model");
}
protected override void UnloadContent()
{
}
// デフォルトで1/60秒固定で呼び出される
protected override void Update(GameTime gameTime)
{
//if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();
//ゲームパッドに関する情報取得用
GamePadState gamepadstate = GamePad.GetState(PlayerIndex.One);
//trueの場合、ゲームパッドが接続されている
if (gamepadstate.IsConnected)
{
//終了
if (gamepadstate.Buttons.Back == ButtonState.Pressed) this.Exit();
//左スティックの位置を取得
model_pos.X += gamepadstate.ThumbSticks.Left.X * 0.2f;
model_pos.Z -= gamepadstate.ThumbSticks.Left.Y * 0.2f;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
foreach (ModelMesh mesh in samplemodel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
//デフォルトのライティングを有効
effect.EnableDefaultLighting();
//ワールド行列を設定
//Matrix.CreateTranslationメソッドで、移動用のマトリックスを作成
effect.World = Matrix.CreateTranslation(model_pos);
//ビュー行列を設定
effect.View = Matrix.CreateLookAt(new Vector3(16.0f, 8.0f, 18.0f), Vector3.Zero, Vector3.Up);
//射影行列を設定
effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
GraphicsDevice.Viewport.AspectRatio,
1.0f, 10000.0f);
//スペキュラカラーの設定
effect.SpecularColor = new Vector3(0.4f, 0.4f, 0.4f);
}
mesh.Draw();
}
base.Draw(gameTime);
}
}
}
前回、サンプルコードに追加した、leftmoveフィールドは不要となったので削除した。
前回のサンプルコードのこの1行(削除)。
bool leftmove = false; //Uターン用
今回、ゲームパッドに関する処理を記述したのは、Update()メソッドである(他のメソッドは、前回のサンプルコードと変更無し)。
//if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();
上の1行は、元々テンプレートが自動的に生成したコードで、ゲームパッドのBackボタンを押すと、プログラムが終了する処理である。
このコードは、新たに追加したゲームパッド関連処理の方に記述し直したので、コメントとした。
新たに追加したゲームパッド関連処理は・・・
//ゲームパッドに関する情報取得用
GamePadState gamepadstate = GamePad.GetState(PlayerIndex.One);
//trueの場合、ゲームパッドが接続されている
if (gamepadstate.IsConnected)
{
//終了
if (gamepadstate.Buttons.Back == ButtonState.Pressed) this.Exit();
//左スティックの位置を取得
model_pos.X += gamepadstate.ThumbSticks.Left.X * 0.2f;
model_pos.Z -= gamepadstate.ThumbSticks.Left.Y * 0.2f;
}

Xbox LIVEインディーズゲームとしてリリースする場合、PlayerIndex.Oneだけでは無く、複数のゲームパッドに対応させる必要があります。
詳細は、プレイテストとピアレビューでチェックすべき項目のチェックリストを参照して下さい。
2010年5月24日追記
ゲームパッドの左スティックはこれ。

これだけのコードで、スティックの傾き具合にもきちんと対応している。
xnaは、ゲームパッドに関する情報を、かなり簡単に取得できるようだ。

また、それに合わせて、ゲームパッドに関する処理を修正。
自キャラとなる立体モデルも、平行移動だけでは無くて、Y軸を中心とした回転を加えてみた(回転行列x移動行列)。
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace WindowsGame1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Model samplemodel; //自キャラの立体モデル
Model samplemap; //マップの立体モデル
Vector3 camera_pos; //カメラの位置
Vector3 model_pos = Vector3.Zero; //自キャラの位置
float model_rotate_y; //自キャラの角度
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//モデルの読み込み
samplemodel = Content.Load<Model>("sample_model"); //自キャラ
samplemap = Content.Load<Model>("sample_map"); //マップ
}
protected override void UnloadContent()
{
}
// デフォルトで1/60秒固定で呼び出される
protected override void Update(GameTime gameTime)
{
//ゲームパッドに関する情報取得用
GamePadState gamepadstate = GamePad.GetState(PlayerIndex.One);
{
//trueの場合、ゲームパッドが接続されている
if (gamepadstate.IsConnected)
{
//終了
if (gamepadstate.Buttons.Back == ButtonState.Pressed) this.Exit();
//立体モデルを左右に回転
model_rotate_y -= gamepadstate.ThumbSticks.Left.X * 0.05f;
//立体モデルの前進と後退
Vector3 vec3 = new Vector3(0, 0, gamepadstate.ThumbSticks.Left.Y * 3.0f);
vec3 = Vector3.Transform(vec3, Matrix.CreateRotationY(model_rotate_y)); //正面
model_pos.Z += vec3.Z;
model_pos.X += vec3.X;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
//カメラの位置を更新
camera_pos = Vector3.Transform(new Vector3(0, 0, -8), Matrix.CreateRotationY(model_rotate_y))
+ model_pos;
//マップの描画
DrawModel(samplemap, Matrix.CreateTranslation(Vector3.Zero));
//自キャラの描画
DrawModel(samplemodel, Matrix.CreateRotationY(model_rotate_y)
* Matrix.CreateTranslation(model_pos));
base.Draw(gameTime);
}
//立体モデルの描画
void DrawModel(Model model, Matrix world)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
//デフォルトのライティングを有効
effect.EnableDefaultLighting();
//ワールド行列を設定
effect.World = world;
//ビュー行列を設定
effect.View = Matrix.CreateLookAt(camera_pos, model_pos, new Vector3(0.0f, 1.0f, 0.0f));
//射影行列を設定
effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
GraphicsDevice.Viewport.AspectRatio,
1.0f, 10000.0f);
//スペキュラカラーの設定
effect.SpecularColor = new Vector3(0.4f, 0.4f, 0.4f);
}
mesh.Draw();
}
}
}
}

カメラの位置とアングルを計算する部分と、自キャラの描画部分・・・
//カメラの位置を更新
camera_pos = Vector3.Transform(new Vector3(0, 0, -8), Matrix.CreateRotationY(model_rotate_y))
+ model_pos;
//自キャラの描画
DrawModel(samplemodel, Matrix.CreateRotationY(model_rotate_y)
* Matrix.CreateTranslation(model_pos));
Matrix.CreateRotationYメソッドの引数(角度)は、ラジアン単位で渡すべきです。
model_rotate_yの値をMathHelper.ToRadiansメソッド(度をラジアンに変換)を用いて、ラジアン単位に変換してから渡して下さい。
また、model_rotate_yの値が360度を超えたり、0度未満になった時の処理も、きちんと組んだ方が良いと思います。
2010年5月24日追記
今回、新たに迷路の立体モデル「sample_map1.x」を追加した(DirectXのX形式ファイル)。

立体モデル「sample_map1.x」ダウンロード
http://mukago.game.coocan.jp/sample/sample_map.x
この立体モデルは、コンテント・パイプラインを使って、プロジェクトに組み込む必要がある。
詳細は、第4話:コンテント・パイプラインを参照。
アセット名は、デフォルトの「sample_map」とした。
また、この立体モデルは、左の画像のビットマップファイル(サイズは64x64)をテクスチャとしている。ファイル名は「map1.bmp」。
テクスチャ「map1.bmp」ダウンロード
http://mukago.game.coocan.jp/sample/map1.bmp
このビットマップファイルは、プログラム中で直接操作しない。
よって、プロジェクトに組み込む際に、コンテント・パイプラインを利用しない方が良いだろう。
そこで、エクスプローラ等のファイラを使って、プロジェクトのContentフォルダに、手動でファイルをコピペする。
詳細は、第6話:補足を参照。


