Game building日誌 その5「3日目、プログラム開始」

 

9月21日(火) 10:00AM 仕事発生、6時間のロス

Game Building中はゲームを作ることが優先されますが、優先度の高いバグや他のチームからの質問などには対応しないといけません。そんな訳で、今日は出社した途端に優先度の高いバグの検証作業などが入り、Game Buildingの作業は一旦中止になってしまいました。

9月21日(火) 03:53PM 作業再開、ゲームステート管理サンプルを雛形に

それではいよいよコーディング開始です。まずは、ゲームの状態の管理サンプルをダウンロードして、プロジェクト名と、GUIDを変更します。GUIDを変更するのはXbox 360に配置するときに、このGUIDが他のプロジェクトと見分けるIDとなるので、同じGUIDのプロジェクトを配置すると上書きしてしまうという問題を避けるためです。

ゲームステート管理サンプルはおそらくクリエーターズクラブオンラインサイトの中では最も使われているサンプルでしょう。今回のGame Buildingでも殆どのゲームがこのサンプルを雛形にしてメニュースクリーンを作っていました。

注: 4.0版のサンプルは既に出ているのですが、サイトのバグでフレームワークの表示部分が2.0のままになっていることに注意してください。サンプル名+ _4_0.zipとなっているものは4.0版です。

20101005-40sample

今回はSci-Fiものということで、それっぽいフォントに差し替えました。

それ以外にもデバッグサンプルのコードや、自作しておいたLightWaveのインポーター、プロセッサをプロジェクトへ追加しました。

私がゲームを作るときに必ずあるのがDrawContextとGlobalというクラスです。DrawContenxtはその名のとおり、描画するのに必要な情報をまとめて持っておくクラスで、View、Projectionを設定するメソッドがあり、設定した場合に鏡面光を計算するのに視線ベクトルや、BoundingFrustumなどを生成するようになっています。描画メソッドにはこのクラスのインスタンスを渡して描画するようになっています。

また、Globalクラスはゲームの中で一度生成したら破棄しないものを入れておくためのクラスです。例えばゲーム全体に共通するグラフィクス関連のリソースなどを入れています。また、このクラスはstaticではなくSingletonパターンを使っていて、Global.Current.XXXXの様にメンバにアクセスします。staticクラスじゃない理由としては、インスタンスを作る時期を明示的にコントロールできる、拡張メソッドを追加できる(拡張メソッドはインスタンスメソッドのみに使える)、後でインスタンスクラスにしたい時に移行が楽になる、といった感じです。

また、この段階で将来的に作るであろうソースコードの種類を分類してフォルダーとして作っておきます(中身はカラ)。私は習慣的にこのフォルダの名前をGameXXXXといった名前にします。これはEnemyというフォルダ名を作ってしまうと、その中に更にEnemey.csという名前のクラスを作ることになってしまうので、名前衝突が起きてしまうのを避けるためです。

この段階では特に名前にこだわらずにゲームにありそうな名前を適当に付けていくだけです。そんな感じで作業開始から20分足らずの段階で下図のようなソリューションになります。 20101005-placeholder

なぜ、この段階でカラのフォルダーだけ作るのかというと、作業の全体量を早めのうちに把握できるからです。あくまでゲームを完成させるのが目的なので、一部分だけ気合を入れすぎて作ってしまうと、他の部分とのバランスが取れなくなったりして、スケジュールが差し迫った時には他の部分を作りこむ余裕が無くなってしまった、なんていうことが良くあります。また、作業を進めていく途中でも「ここまでやった」という達成感があり、モチベーション維持にも役立ちます。

9月21日(火) 04:10PM マテリアルバッチング

雛形ができたので実際にプログラムを組んでいきます。LightWaveのインポーターを作った時にテスト用に描画プログラムも書いたのですが、なにぶんテスト用だったので下図の左側のシーンツリーを素直に描画するだけのものでした。そこで、今回は簡単なマテリアルバッチ変換をして描画するように変更しました(マテリアルバッチの効果についてはGamefest Japan 2008デモプログラムを参考)。

「最適化は必要にならない限りしない」という言葉がありますし、私も同じ事を言ってるので、「おいおい、言ってることとやってることが違うじゃないか」と突っ込みが入りそうですが、実は今回マテリアルバッチを最初に組んだのには最適化以外の理由があります。

material-batch

マテリアルバッチは描画高速化に有効な手立てのひとつですが、他にもシーンツリーがノード毎の座標空間を渡り歩いて「このノードのモデルを描画」という風に描画するのに対して、マテリアル毎に渡り歩いて「このマテリアルを使っているノードを描画」という風に描画の指定の仕方が違うという特徴があります。

実際のゲームではマテリアルをアニメーションさせたりすることが多いので、そういうときにもマテリアルバッチを使っていると処理がしやすくなります。

今回はまさにそれに該当するケースで、敵のエンジン(と思われる)部分の色をアニメーションさせたかったからです。例えば下図の場合では白い部分がアニメーションさせたい部分です。マテリアルバッチにしておけば、こまエンジン部分の色を一箇所で変えるだけで、このマテリアルを使っている全てのモデルに反映させることができます。

20101005 faker-back

また、この部分を別のレンダーターゲットに描画し、ぼかした後に元のシーンと重ねることで下図のようにまぶしい光の表現もできるなぁ、と、この時は考えていました。

20101005 faker-bright

9月21日(火) 07:42PM テストシーン再生

マテリアルバッチ処理のコードを書いた後はLightWaveから出力したシーンをアニメーションさせる部分をプログラム。今回のゲームは最初から最後までプレイすると6分程掛かります。これをひとつのシーンファイルにまとめてしまうと、敵の出現タイミングを合わせたりするのに時間が掛かるので、複数のシーンファイルに分けておいて連続で再生するようにしました。コード的には以下のように単純なものですが、このテーブルを変更することでテストしたいシーンからすぐに始められるので時間の節約になります。

 GameScene[] scenes = 
{
    new StartScene("game-scene01"),         // スタート
    new GameScene("game-scene02"),          // ロウンチ
    new WarpScene("game-scene03"),          // ワープ
    new AsteroidBeltScene("game-scene04"),  // アステロイドベルト
    new BattleShipScene("game-scene05"),    // 戦艦
    new MotherShipScene("game-scene06"),    // 空母
    new PlanetScene("game-scene07"),        // 惑星
};

これらの「GameScene」クラスを管理するGameScenePlayerクラスがあり、このクラスで現在再生中のゲームシーンの管理と、それぞれのシーンの連続再生をするようになっています。また、GameSceneは再生中にGameComponenetと同じようにUpdateとDrawが呼び出されるのでシーン毎に敵パターンなどを管理できるようになっています。

とりあえず、シーンの管理周りができたのでLightWaveでこの二日間でモデリングした3Dモデルを配置し、簡単なカメラの移動アニメーションを作り、実際にゲームに読み込んでテストしました。

hrku

さて、テストシーンでは殆どのモデルが正常に表示され、カメラのアニメーションも問題なく再生されました。ですが、ひとつDeath Ball(上図の左側にあるピンク色の四角形のモデル)のマテリアルが逆になって表示されているという問題がありました。

9月21日(火) 09:30PM インポーターのバグとり

マテリアルが逆になっている問題ですが、丁度マテリアルバッチのプログラムを追加したので、その線が濃厚なのですがデバッグしてみると、マテリアル情報が元から逆になっていることが判明したのでインポーターのデバッグを開始しました。

コンテント・パイプラインのデバッグはここで紹介した方法のうち、デバッガをアタッチする方法を使っています。Visual Studio 2010を二つ起動させ、二つ目のVisual Studio 2010からゲームのプロジェクトを開いているVisual Studio 2010にアタッチします。

問題の起きるモデルと起きないモデルの比較をしながら、LWOファイルインポーターをデバッグしはじめて1時間半、LWOファイルのマテリアルの参照インデックスはマテリアルの宣言順ではなく、TAGSチャンクと呼ばれるデータの中で文字列が宣言されている順番だという仕様書読み間違いが原因でした。

9月21日(火) 11:00PM LWSプロセッサへ機能追加

インポーターのバグをとったついでに、LightWaveのシーンファイルであるLWSファイルを処理するプロセッサに新しい機能を追加することにしました。

LWSファイルのプロセッサはスキニングモデルサンプルと同様にコンテントビルド時にアニメーションデータをサンプリングするようになっていて、LightWaveで指定したフレームレートでサンプルするようになっています。

規定値では30FPSなので、この値をプロセッサパラメーターで設定できるようにし、60FPSでサンプリングするようにしました。

これで滑らかなアニメーションが再生されるようになりました。

9月22日(水) 02:30AM モデルのスケール調整

LightWaveで作ったデータをゲーム内で表示、動作させる部分が完成したので、実際にゲームのシーンを作る準備が整いました。実際にシーンを作っていく前に、モデリングする時にサイズを気にせずにして作ったモデルのサイズ調整をします。

オリジナルのゲームの設定では戦艦のサイズが500m、母艦に至っては2Kmという大きさになっています。このままの数字でも問題ないのですが、これだけ大きなスケールには馴染みがないので実感がなく、シーンを作っている時に手探りになってしまうことがあります。

そこで、今回は設定の1/100スケールにします。つまり、500mの大きさの戦艦は5mになり、18mの設定の敵小型戦闘機は18cmの大きさになるわけです。このサイズになると、部屋の中に5mの大きさの戦艦があって、自分の手には18cmの大きさの模型を手に持ち、童心に返って「ブーン」なんて言いながら飛行経路を考えるなんてことが容易にできるようになります。

FPSなどの場合は現実にあるサイズをそのまま使ったりしますが、今回のようなSFものの場合はゲームのスケールを馴染みのある大きさに縮尺することでゲームプレイ部分をいつでも容易に考えることができます。

 

Game Building発表まで、あと3日……

つづく