|
第三回 マップを出して似非FPS 前回、md2形式のモデルを表示するまでを行いましたが、今回はこれにBSPマップを表示し、Quake風のカメラ移動を取り入れて、FPSっぽくマップの中を歩き回れるようにしたいと思います。 BSPマップって何? BSPマップとは、Quake、HalfLife等のFPS系シューティングで主に使用される3Dマップのフォーマットで、もともと視界外のモデル表示を省略するBSPというアルゴリズムが使用されていたことからBSPマップと呼ばれています。 BSPマップを作成するには通常のモデリングソフトではなく、専用のマップ作成ツールを使って作成するのが一般的です。実際のマップの作成に関しては、番外編という形で別途解説しています。 マップNodeを追加する それでは、前回のソースを元に、マップを表示するようにしてみましょう。 マップデータを用意する まずはマップデータを用意しなければなりません。 アーカイブからファイル取り出し Irrlichtは、zip(pk3)形式で圧縮された書庫ファイルから、解凍せずにファイルをロードすることが可能です。 main.cppに以下のように追加してください。
ISceneManager *Scene = Device->getSceneManager();
Device->getFileSystem()->addZipFileArchive("simplemap.pk3");
Scene->addCameraSceneNode(0, vector3df(0,10,-40), vector3df(0,10,0));
addZipFileArchive()関数を使って、Irrlichtのファイルシステムにzip形式の書庫ファイルを追加すると、ファイルをロードする際に、追加した書庫ファイル内を検索するようになります。
マップNodeを作る 続いて、マップファイルを読み込んで、ISceneManagerにNodeとして追加しましょう。 ISceneManager *Scene = Device->getSceneManager();
Device->getFileSystem()->addZipFileArchive("simplemap.pk3");
IAnimatedMesh *MapMesh = Scene->getMesh("simplemap.bsp");
ISceneNode *MapNode = Scene->addOctTreeSceneNode(MapMesh);
MapNode->setMaterialFlag(EMF_LIGHTING, false);
Scene->addCameraSceneNode(0, vector3df(0,10,-40), vector3df(0,10,0));
simplemap.pk3の中にsimplemap.bspというマップデータがありますので、それをgetMesh()関数でロードして、IAnimatedMeshオブジェクトを作ります。.bsp形式のファイルを読み込むと、内部で使用しているテクスチャファイルも自動的に読み込まれます。 続いて、今読み込んだIAnimatedMeshをISceneManagerに登録するのですが、マップを登録する際には通常のモデルとは違ったNodeとして登録します。そのため、前回使用したaddAnimatedMeshSceneNode()ではなく、addOctTreeSceneNode()関数を使用します。
続いて、今回のプログラムでは光源を登録していないので、setMaterialFlag()関数で光源処理をOFFにしておきます。これは前回説明したので詳細は省略します。 マップ位置の調整 とりあえずこれでマップの表示はできるはずですので、一度実行してみましょう。
めでたくマップは表示されましたが、Sydney姐さんが腰まで埋まってて気持ち悪いですね。視点も低いので妙な感じです。マップの位置を下げましょう。以下のコードを追加してください。 Device->getFileSystem()->addZipFileArchive("simplemap.pk3");
IAnimatedMesh *MapMesh = Scene->getMesh("simplemap.bsp");
ISceneNode *MapNode = Scene->addOctTreeSceneNode(MapMesh);
MapNode->setMaterialFlag(EMF_LIGHTING, false);
MapNode->setPosition(vector3df(0,-24,0));
Scene->addCameraSceneNode(0, vector3df(0,10,-40), vector3df(0,0,0));
setPosition()関数はNodeの位置を設定します。この関数には以後たくさんお世話になると思います。
再度実行して、マップの位置が適切になったかどうか確認してください。
FPSっぽくグリグリと FPS風カメラ めでたくマップも出たことですし、マップの中をグリグリと動けるようにしましょう。 Irrlichtには、FPS系のゲームを実現するため、Quake風の入力に対応したカメラがあらかじめ用意されていますから、今回はそれを使用することにしましょう。 main.cppの中のこの部分を MapNode->setPosition(vector3df(0,-24,0));
Scene->addCameraSceneNode(0, vector3df(0,10,-40), vector3df(0,0,0));
IAnimatedMesh *SydneyMesh = Scene->getMesh("sydney.md2");
以下のように書き換えてください。 MapNode->setPosition(vector3df(0,-24,0));
ICameraSceneNode *Camera = Scene->addCameraSceneNodeFPS();
Camera->setPosition(vector3df(0,10,-40));
Device->getCursorControl()->setVisible(false);
IAnimatedMesh *SydneyMesh = Scene->getMesh("sydney.md2");
addCameraSceneNodeFPS()関数を使ってカメラNodeを追加すると、以後Quake風の操作でカメラが動かせるようになります。↑で前進、↓で後退、←→で左右平行移動(カニ歩き)、マウスでカメラ方向の移動です。
FPSカメラが作られた直後は、カメラ位置が(0,0,0)になっていますので、setPosition()関数を使って前回のカメラ位置のあたりに持ってきましょう。 マウスポインタがどうせ動かなくなるなら、マウスポインタを消してしまいましょう。
それでは実行してみてください、カメラが動かせるはずです。
とはいえ、まだ当たり判定を取っていませんので、カメラが壁を突き抜けてずんずん進んでしまいますね。 FPSっぽいところで、FPSを表示してみる あれこれ機能も載ってきたところですし、FPS(Frame Per Second)でも表示してみましょう。 SydneyNode->setMD2Animation(EMAT_RUN);
int lastFPS = -1;
int lastPrims = -1;
while(Device->run())
{
Driver->beginScene(true, true, SColor(0,100,100,160));
Scene->drawAll();
Driver->endScene();
int fps = Driver->getFPS();
int prims = Driver->getPrimitiveCountDrawn();
if (lastFPS != fps || lastPrims != prims)
{
wchar_t tmp[1024];
swprintf(tmp, 1024, L"Irrlicht A GoGo - Tutorial (fps:%d) Triangles:%d", fps, prims);
Device->setWindowCaption(tmp);
lastFPS = fps;
lastPrims = prims;
}
}
getFPS()関数でFPSを、getPrimitiveCountDrawn()関数で描画した三角形の数を取得しています。
これでFPSが表示されるはずです。モデルやマップを画面外に追い出すなりして、fpsとTrianglesがどのように変化するか見てください。このマップは小さすぎてOctTreeの効果がわかりにくいかもしれませんので、Irrlichtのサンプルに付属のマップファイルに差し替えてみるのもいいでしょう。
ここまでのソースをこちらに置いておきます。結構長くなってきたので、コメント等を入れてあります。 |