今後、力をいれていきます。
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話:補足を参照。