Irrlicht学习备忘录2 Quake3Map
2Quake3Map 官方代码 ($sdk)\examples\02.Quake3Map 这个例子演示了向 irr 引擎中载入一张 Quake3 地图文件以及创建一个用户控制的摄象机。它跟上一个例子 HelloWorld 一样简单,其实应该是更简单。它比上个例子少了 GUI 部分,增加了使用压缩文件的方法,剩
2Quake3Map
官方代码($sdk)\examples\02.Quake3Map
这个例子演示了向irr引擎中载入一张Quake3地图文件以及创建一个用户控制的摄象机。它跟上一个例子HelloWorld一样简单,其实应该是更简单。它比上个例子少了GUI部分,增加了使用压缩文件的方法,剩下的内容都是上个例子中已有的。至于多出来渲染方式选择菜单,帧速统计这部分代码,应该可以说跟irr彻底无关,这是任何一门编程语言入门时就练习过的内容。
irr名字空间下有五个子命名空间,core,scene,video,io,gui。在这个例子中,可能引擎作者为了让学习者熟悉各空间的负责什么功能,并没有使用usingnamespace xxx的方式声明使用子名字空间。
下面代码为例子中的选择irr驱动设备代码。在命令行界面中做了个简单的菜单选择界面,通过swicht语句判断选中的驱动类型。
video::E_DRIVER_TYPEdriverType;
printf("Pleaseselect the driver you want for this example:\n"\
"(a) OpenGL 1.5\n (b) Direct3D 9.0c\n (c) Direct3D 8.1\n"\
"(d) Burning's Software Renderer\n (e) Software Renderer\n"\
"(f) NullDevice\n (otherKey) exit\n\n");
chari;
std::cin>> i;
switch(i)
{
case'a': driverType = video::EDT_OPENGL; break;
case'b': driverType = video::EDT_DIRECT3D9;break;
case'c': driverType = video::EDT_DIRECT3D8;break;
case'd': driverType = video::EDT_BURNINGSVIDEO;break;
case'e': driverType = video::EDT_SOFTWARE; break;
case'f': driverType = video::EDT_NULL; break;
default:return 1;
}
该段代码在irr的例子中经常出现,在后面其他例子中,它被封装到driverChoiceConsole函数接口中,头文件driverChoice.h。
下面是使用压缩文件的代码。方法很简单,通过irr的设备指针提供的获取irr文件系统。
irr文件系统中addFileArchive接口提供了访问zip压缩文件的功能。在头文件中能看到该接口的详细说明。
device->getFileSystem()->addFileArchive("../../media/map-20kdm2.pk3");
调用addFileArchive后,解压的文件在irr文件系统中的位置与程序文件在相同目录下,但在操作系统文件系统中看不到。addFileArchive接口中有参数指定解压后的文件目录是否有效,设置无效标记,压缩文件中的文件目录将被忽略,所有解压后的文件都在同一目录下。
scene::IAnimatedMesh*mesh = smgr->getMesh("20kdm2.bsp");
这行代码在HelloWorld中已经出现过,唯一不同的是getMesh中的文件名。20kdm2.bsp文件是从map-20kdm2.pk3文件中解压出来的。因解压后的文件位置与程序文件在同一目录,因此使用相对路径访问,就只需直接给出文件名就行了。
scene::ISceneNode*node = 0;
if(mesh)
node= smgr->addOctreeSceneNode(mesh->getMesh(0), 0, -1, 1024);
这里添加场景节点的方法与HelloWorld的也很相似,不同是以前用的是addAnimatedMeshSceneNode添加动画网格场景节点,这次用的是addOctreeSceneNode添加八叉树场景节点。从节点名称上可以知道,动画网格节点,意味着该节点是会动的。这次的八叉树场景节点,是用八叉树对该节点模型进行优化,它只对静态模型有效。通常地图、地形这类静态模型体积非常大,使用的顶点数极其庞大,同时将所有顶点数据传递给显卡处理,对带宽资源是种浪费,同时也让显卡对不需要显示的部分也进行了大量运算,这是对硬件资源使用的浪费。使用八叉树优化后,通过对八叉树的裁剪,得出每次显示区域的顶点数据,只传送该部分数据给显卡,可以明显提高显示速度。irr通过八叉树节点把这些优化功能全做了。
if(node)
node->setPosition(core::vector3df(-1300,-144,-1249));
设置场景节点的位置坐标。这里同样在HelloWorld中出现过。
smgr->addCameraSceneNodeFPS();
这行看起来很眼熟,就是比原来见到的多了FPS这个尾巴。熟悉游戏的人,一看FPS就知道只的是什么。因此这行是添加了一个FPS视觉的摄像机。玩FPS游戏时是如何控制摄像机移动的,这里也一样。只需addCameraSceneNodeFPS这么一句,就已经把FPS摄像机及移动方式都解决了。
device->getCursorControl()->setVisible(false);
这句,用词霸查出每个单词的意思,连起来一读也就明白。irr设备获取光标控制,设为光标不显示。FPS游戏里本来就不需要鼠标光标,这里把鼠标光标关闭,没什么可奇怪的。
intlastFPS = -1;
while(device->run())
{
if(device->isWindowActive())
{
driver->beginScene(true,true, video::SColor(255,200,200,200));
smgr->drawAll();
driver->endScene();
intfps = driver->getFPS();
if(lastFPS != fps)
{
core::stringwstr = L"Irrlicht Engine - Quake 3 Map example [";
str+= driver->getName();
str+= "] FPS:";
str+= fps;
device->setWindowCaption(str.c_str());
lastFPS= fps;
}
}
else
device->yield();
}
这段代码跟原来见到的仍然很相似,就是中间多了几行。仔细看看多出来的这几行,就是设计了一个计数器,用来记录显示帧速。irr设备提供的getFPS()接口可以直接获取当前的显示帧速,因此不再需要用计时器和累加器在循环里进行帧速的计算,这点很方便。 core::stringw字符串类型,看到前面的名字空间,应该知道这是irr自己的字符串类型。为何不用STL字符串?我也觉着奇怪,在后面还不断的发现很多常用的泛型,仍然不是STL而是irr自己的。不过看了它们的代码后,感觉他们比STL的更简洁写,少了一些不常用的东西,也增加了一些STL没有的功能。可能是开始写irr时,STL还没成C++标准的一部分,要么是STL用在游戏引擎中速度方面不够理想。不过irr的字符串类型我挺喜欢的,它可以通过+=运算符,直接将数字、字符串直接加入原有的字符串,而且字符串类型并不区分宽窄,它会在本地字符集和Unicode之间自动转换,挺方便的。
将处理好的字符串传递给setWindowCaption,显示在窗口标题栏上。
程序编译好后,就可以进去游览下这个Quake3Map了,操作完全是FPS操作方式,退出时需要按Alt+F4。就这么几行代码,就实现了FPS游戏的最基本样子,感觉的确有点振奋人心。似乎用它做出自己的游戏并不难。