--------------------西昌.何雨锋 鼠标抓取
让鼠标抓住东西也就是鼠标直接碰撞检测,那是肯定不行的,至少用对象
TVCollisionResult是决对行不通的,因为那会出现实时错误,那么怎么判断一个鼠标已经对准了一个东西的什么位置呢?
只有从global上想办法了,因为VB下有而C++中没有的什么数学函数啦,什么其他类型啦都在里面找得到。
global1->MovePoint(&结果点,&源点,x角度,y角度,距离)
这个函数的作用是已知一个源点坐标,也知道这个源点坐标要转xy角度对准了一个方向,请问距离多少多少的那个点的三维坐标。
通过这个函数,我们就可以让源点是摄像机的点,再知道转动的角度(就是那两个xangle和yangle)然后再将幅度转换成角度就可以
得到固定距离处那个点的坐标,这样我们就得到了从摄象点到lookat点的一条直线,用高级碰撞不就可以知道撞到哪里了吗?
以下是具体使用方法:
****************
global1->MovePoint(&vector3,&vector2,-xangle * 180 / 3.14,90-yangle*180/3.14,2000);
//这样vector3就是vector2点出发,旋转xangle与yangle后距离2000的点了。
//这样就得到了屏幕正中所发射出的直线了。
****************
当然了,还有一个函数为global1->MousePickVector(mousex,mousey,&vector2,&vector3);
也就是将鼠标的位置形成两个点,一个是观察起点,一个是鼠标指向的位置点,
但是一定要注意,这里的mousex,mousey必须是input1->GetAbsMouseState()得到的值,而不是input1->GetMouseState()得到的值,否则出来的线就会偏很远。
下面的例子是一个用鼠标点中陆地,就将人物放在碰撞位置的例子:
*****************
TV_COLLISIONRESULT col1; //注意,这里绝对不能用ITVCollisionResult,否则实时错误必然出现
//甚至不需要建立出来。
if(mouse_b1) //当鼠标按下时,判断是否碰撞
{
input1->GetAbsMouseState(&mousex,&mousey,(short *)&mouse_b1,(short *)&mouse_b2,(short *)&mouse_b3);
//必须是input1->GetAbsMouseState()得到的值,而不是input1->GetMouseState()得到的值
global1->MousePickVector(mousex,mousey,&vector2,&vector3);
//得到鼠标的起点与终点。
scene1->AdvancedCollision(&vector2,&vector3,&col1,TV_COLLIDE_LANDSCAPE,TV_TESTTYPE_ACCURATETESTING,tvtrue);
//与陆地进行碰撞检测,检测到的结果给col1
if(col1.hascollided)
{
man2->SetPosition(col1.collisionimpact.x,col1.collisionimpact.Y,col1.collisionimpact.Z);
//注意这里碰撞点的xyz的大小写。
}
}
//如果是第一人称射击,这里就改成
global1->MousePickVector(mousex,mousey,&vector2,&vector3);//这里只需要得到vector2,也就是摄像机的位置,vector3鼠标点的位置在这里没用
global1->MovePoint(&vector3,&vector2,-xangle * 180 / 3.14,90-yangle*180/3.14,2000);
//这里是以玩家的当前位置出发,旋转的x角度与y角度,距离2000的一个点(也就是屏幕正中瞄准的那个点)
//然后再做同上的碰撞检测就知道中心瞄准器瞄准了什么了。
******************
碰撞到的结果装在TV_COLLISIONRESULT结构里,它有以下成员可供访问:
collisionnormal 普通的点
collisionimpact 碰撞的点
distance 碰撞距离
U U barycentric coordinate for collided face.
v V barycentric coordinate for collided face.
faceindex 面的index(for meshs)
GroupIndex 碰撞组的index(for meshs)
hascollided 是否碰撞
collidedobjecttype long 碰撞物体类型
entityid 角色id(for actors和actor2)
MeshID 物体的id(for mesh)
landscapeid 陆地的id (for landscape)
boneId 骨骼的id(for actor2 with bones)
如果要抓取的对象是多个,有的是一个,有的是用一个数组建立出来的多个,那么会发现这些对象的ID很可能是岔开了的,
怎么才能准确的判断出是哪一个对象被抓取了呢?
一般在碰撞后只能用循环的办法判断出是哪个被抓取了,比如mesh:
scene1->AdvancedCollision(&vector2,&vector3,&col1,TV_COLLIDE_MESH,TV_TESTTYPE_ACCURATETESTING,tvtrue);
if(col1.hascollided)
{
tickid=col1.MeshID;
for(i=0;i<8;i++)
{
if(col1.MeshID==obj1[i]->GetMeshIndex())
obj1[i]->SetPosition(0,0,0);
}
}
但是要把所有的物体遍历到可不容易啊.....,是不是TVCollisionResult要好一些呢?
常数:
CONST_TV_OBJECT_TYPE
{
TV_COLLIDE_MESH = 1
TV_COLLIDE_TERRAIN = 2
TV_COLLIDE_LANDSCAPE = 4
TV_COLLIDE_BSPTREE = 8
TV_COLLIDE_OCTREE = 16
TV_COLLIDE_ACTOR = 32
TV_COLLIDE_PHYSICOBJECT = 64
TV_COLLIDE_ACTOR2 = 128
}
CONST_TV_TESTTYPE
{
TV_TESTTYPE_BOUNDINGBOX = 1 Uses ray-boundingbox collision
TV_TESTTYPE_BOUNDINGSPHERE = 2 Uses ray-boundingsphere collision
TV_TESTTYPE_ACCURATETESTING = 3 Uses ray-triangle collision
TV_TESTTYPE_MDL_HITBOXES = 4
}
------------------以下为解释贴:
在VB中一般用TVCollisionResult对象,这个对象用起来很容易,如col=land->mousepick(..)、col=scene->mousepick(...)的都可以,但是在C+下面无论怎么样一用col->iscollision()都会出现实时错误,根本无法使用。
但是这个小组还开发了一个结构(不是对象)叫TV_COLLISIONRESULT,这个结构可以被用到一些高级碰撞的检测中。(而且这些碰撞检测函数还只能用TV_COLLISIONRESULT结构而不能用TVCollisionResult对象),比如:
scene1->AdvancedCollision(&vector2,&vector3,&col1,TV_COLLIDE_LANDSCAPE,TV_TESTTYPE_ACCURATETESTING,tvtrue);
中的col1就是TV_COLLISIONRESULT,这个函数用来检测vector2,vector3两点连线是否穿过land,那么如何把mouse的二维坐标转换成场景中的三维点呢?同样,在Global这个包罗了很多函数的对象中有两个函数:
global1->MousePickVector(mousex,mousey,&vector2,&vector3); //当然这里的mousex,mousey都得从GetABSMouseState(...)中而非GetMouseState()中得到。
这样就获得了两个点,vector2代表了摄象机的位置(当然也可以建立出摄象机然后用场景相机赋给它,但那就要稍复杂些),vector3代表的就是鼠标在三维场景中点中的那个点了(当然那个点很远很远),得到了这两个点再配合上前面的高级碰撞检测函数就实现了VB中的TVCollisionResult col=scene->mousepick(...)的同等功能了.
如果是第一人称射击的话,这个过程还可以简化至:
global1->MousePickVector(mousex,mousey,&vector2,&vectorx); //这里的vectorx毫无用处,因为根本没必要知道鼠标点中哪里,我们要的实际就是camera.position :)
global1->MovePoint(&vector3,&vector2,-xangle * 180 / 3.14,90-yangle*180/3.14,2000);
//这个函数的意义在于已知一个空间点vector2(实际就是主角的位置),以这个空间点为中心,沿x,y分别转动xangle,yangle幅度,距离2000的得到的点坐标vector3 (这里的xangle与yangle是幅度,我只是用些公式把它转化成了角度而已,还记得VB例子中所有第一人称动作的教程都是只能左转右转而不能象CS那样左右平移的吗?而VC6里虽然教程很少,但是凡FPS的都是左右平移的,而望向方向与绝对坐标的夹角就是这个xangle与yangle,为了得到这个公式,身为数学盲的我花了整整3个热得不得了的晚上的时间才实践出来的,这个公式稍微修改后还可用于my枪始终on my front这个问题上),这两个点就是屏幕中央(实际就是瞄准器中央而不是鼠标)发出子弹的弹道了.
----------------------------------