Irrlicht引擎里的冲突检测与响应

这是Irrlicht SDK中给的一个例子,用来演示如何在Irricht中冲突检测与响应,其它的例子还有十三个,俺会陆续翻译出来。自己英语水平很洼,但对翻译又有点瘾,所以就帖到这里来,有译错或表达不好的地方请指正。

 

 例7,碰撞检测与响应
  这一节,我将演示如何在Irrlicht引擎里进行碰撞检测。有三种方法:自动的碰撞检测,例如上下楼梯时移动全局坐标;手工拾取三角形和场景结点。
  演示程序效果图:

  开始吧!
  简单起见,我们拿那个加载并显示Quake3地图的例2开刀:在里面四处走动并从中拾取三角形。另外,为了说明场景结点的拾取我们再放三个精灵在里面。下面的代码启动引擎并加载Quake3地图。不再多加解释(详情参见例2)。 

 

#include  < irrlicht.h >
#include 
< iostream >
using namespace irr;


#pragma comment(lib, 
" Irrlicht.lib " )


int  main()

{

  
// let user select driver type

  video::E_DRIVER_TYPE driverType; 
printf(
"Please select the driver you want for this example: "
    
" (a) Direct3D 9.0c  
(b) Direct3D 8.1
 (c) OpenGL 
1.5 "  
  " (d) Software Renderer
 (e) Apfelbaum Software Renderer "    "
 (f) NullDevice  (otherKey) exit
");  
char i; 
 std::cin 
>> i; 
 
switch(i) 
 
{  
case 'a': driverType = video::EDT_DIRECT3D9;break;  
case 'b': driverType = video::EDT_DIRECT3D8;break;  
case 'c': driverType = video::EDT_OPENGL;   break;  
case 'd': driverType = video::EDT_SOFTWARE; break;  
case 'e': driverType = video::EDT_SOFTWARE2;break;    
case 'f': driverType = video::EDT_NULL;     
break;  default
return 0
 }
    

  
// create device  IrrlichtDevice *device = createDevice(driverType,

     core::dimension2d
<s32>(640480), 16false);

  
if (device == 0)   
        
return 1// could not create selected driver. 
 video::IVideoDriver* driver = device->getVideoDriver();  

scene::ISceneManager
* smgr = device->getSceneManager();  
device
->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
    scene::IAnimatedMesh
* q3levelmesh = smgr->getMesh("20kdm2.bsp");
    scene::ISceneNode
* q3node = 0;


    
if (q3levelmesh)
        q3node 
= smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));

 

  到此为止,我们已经像例2那样加载了Quake3地图。接下来的情况有所不同:我们创建了一个三角形的选择器。这是一个类,你可以用它来从场景结点中拾取三角形,以用作各种不同的用途,比如碰撞检测。引擎里有几种三角选择器,它们都可以用ISceneManager来创建。在这个例子中我们创建OctTreeTriangleSelector,你可以照字面意思理解,是的,这是个树状的选择器,“树”就是数据结构里面的树,我们以此来对三角形数目的输出做些优化。这样对像Quake3之类大的地图是很有用的。
  创建完三角形选择器就把它“系”到场景结点上去,此处是q3node。并不是必需这么做,这是“懒汉”式做法,不用再考虑选择器了,比如到底什么时候用不着了才好释放它。


  还是像例2,为了能在Quake3地图里面移动,我们添加一个FPS(First Person Shooter第一人称射击游戏)相机。但这一次,还要给相机加个特殊的animator:带冲突响应的animator(注3)。它会调整与自己关联的场景结点,使它看起来受重力影响并且不会穿墙而过。对于animator,我们要做的唯一的事情就是告诉它世界是个什么样子,场景结点有多大,重力有多大等等。把带冲突响应的animator加到相机上后,就不必再做任何关于碰撞检测的事――一切都是自动的!。下面有关碰撞检测的代码是是用来拾取的。还有一个令人高兴的、很酷的特性:可以把带冲突响应的animator的事附加到任何场景结点上,不只是相机。另外,它也可以与别的场景结点animator混合使用。如此以来,在Irrlicht引擎中使用冲突检测与响应就非常、非常地简单。
  好了,来看一下createCollisionResponseAnimator() 的参数。第一个参数是TriangleSelector,指明碰撞检测完成后世界看起来是个什么样子。 第二个参数是场景结点,指定受碰撞检测影响的对象,在我们的例子中就是相机。第三个定义对象的大小,即椭球半径。试一试:把半径改小后是不是能够靠墙更近呢?下一个参数是重力的大小和方向。你可以将方向设为(0,0,0)以消除重力。最后一个仅用于转换:否则的话,计算好碰撞检测的椭球会包住相机,而相机位于椭球的中央。但是从人的角度,我们习惯于“眼睛在身体的上方”,而眼睛在身体中间是同我们的现实世界相抵触的。所以我们用这个参数把场景结点从椭球中央上移50个单位。好,现在碰撞检测可以起作用了。
 

    scene::ICameraSceneNode *  camera  =              camera  =  smgr -> addCameraSceneNodeFPS( 0 , 100.0f , 300.0f );

    camera
-> setPosition(core::vector3df( - 100 , 50 , - 150 ));



    scene::ISceneNodeAnimator
*  anim  =     smgr -> createCollisionResponseAnimator(

        selector, camera, core::vector3df(
30 , 50 , 30 ),

        core::vector3df(
0 , - 3 , 0 ),

        core::vector3df(
0 , 50 , 0 ));

    camera
-> addAnimator(anim);

    anim
-> drop();


  因为在Irrlicht里碰撞检测并不是很大的一块(引擎要做的事多着呢,译注)。下一节我将描述如何使用两种不同类型的拾取。但在这之前我会为场景稍作准备。需要三个用来拾取的角色:精灵,一个动态光源以照亮它们,一个用来指出交叉点的白板,还有,噢,我得把光标去掉。 :)
 
  为了不致太复杂,我会在渲染循环里进行拾取。我们先定义两个指针用来保存当前和最后一个场景结点,然后进入循环。
  

    scene::ISceneNode *  selectedSceneNode  =   0 ;

    scene::ISceneNode
*  lastSelectedSceneNode  =   0 ;



    

    
int  lastFPS  =   - 1 ;



    
while (device -> run())   if  (device -> isWindowActive())

    
{

        driver
->beginScene(truetrue0);



        smgr
->drawAll();

  用smgr->drawAll()绘制完全部场景后,开始第一次拾取:我们想知道自己正瞧着整个世界坐标中的哪个三角形。另外,准确一些,还想知道这是在Quake3地图中的哪个点。为此我们创建一个三维的射线:从相机位置开始,穿过目标点。
  然后向碰撞管理器询问:这条射线是否同存储在三角选择器里的三角形发生碰撞?如果是,我们画一个三维的三角形并把白板位置设在交叉点上。
 

 

        core::line3d < f32 >  line;

        line.start 
=  camera -> getPosition();

        line.end 
=  line.start  +

         (camera
-> getTarget()  -  line.start).normalize()  *   1000.0f ;



        core::vector3df intersection;

        core::triangle3df tri;



        
if  (smgr -> getSceneCollisionManager() -> getCollisionPoint(

            line, selector, intersection, tri))

        
{

            bill
->setPosition(intersection);

                

            driver
->setTransform(video::ETS_WORLD, core::matrix4());

            driver
->setMaterial(material);

            driver
->draw3DTriangle(tri, video::SColor(0,255,0,0));

        }


  Irrlicht引擎支持的另一种拾取方法是基于包围盒的节点拾取。每个场景结点已有一个包围盒包着,正因如此,拾取速度非常快,例如在拾取相机看到的场景结点时。再说明一次,我们是向碰撞管理器询问得到这个结果的,如果得到了一个场景结点,就通过取消它材质的光照特性而加亮它,当然,如果它不是白板或Quake3地图的话。
 

    selectedSceneNode  =  smgr -> getSceneCollisionManager() ->

          getSceneNodeFromCameraBB(camera);



        
if  (lastSelectedSceneNode)

            lastSelectedSceneNode
-> setMaterialFlag(

                video::EMF_LIGHTING, 
true );



        
if  (selectedSceneNode  ==  q3node  ||

           selectedSceneNode 
==  bill)

            selectedSceneNode 
=   0 ;



        
if  (selectedSceneNode)

            selectedSceneNode
-> setMaterialFlag(

               video::EMF_LIGHTING, 
false );



        lastSelectedSceneNode 
=  selectedSceneNode;


  就这些,下面要做的只是完成绘制。
 

        driver -> endScene();



        
int  fps  =  driver -> getFPS();



        
if  (lastFPS  !=  fps)

        
{

          core::stringw str 
= L"Collision detection example - Irrlicht Engine [";          str += driver->getName();          str += "] FPS:";          str += fps;          device->setWindowCaption(str.c_str());          lastFPS = fps;        }


    }



    device
-> drop();

    

    
return   0 ;

}

 

 

  ――――――――End―――Of―――File ―――――――――
注:
  1.虽然是科技文,但为了便于理解采用意译。
  2.原文见:Irrlicht手册

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红火吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值