sky11811 发表于 2011-9-7 03:10:32

无用教程第(二)集 sky1811

本帖最后由 sky11811 于 2011-9-7 03:51 编辑

CS模式操作器







   80后应该对CS游戏十分熟悉,键盘上WSAD键估计多数已字迹模糊。除了轨迹球外,个人最喜欢CS模式操作器,我不知道这种操作器叫什么中文名字,第一人称射击游戏操作器有些繁琐,就暂时叫CS操作器吧。在OSG2.8.0后的某个版本,出现了这个FirstPersonManipulator,但是稀奇的是代码里有
/// Move camera right by distance parameter.
void FirstPersonManipulator::moveRight( const double distance )
{
assert( 0 && "Not implemented yet." );
}
直到最新版本,这个还是Not implemented yet。呵呵,既然人家不implemented ,那就自己来吧。估计作者对这个操作器有很高的期望值,想做的完美,所以暂时没有实现。我在这里先替作者完成个初稿吧,当然不完美,期待电脑前的您把它做的完美。我在办公室的计算机里对这个操作器做了很详细的改进,可恶的是无法导出,所以不能和大家分享成果,实在是遗憾,今天利用2个多小时的时间,整理思路,又重新在家里做了一次,由于时间短只对重要的部分进行了梳理,并写出来粗糙的文档,请原谅这粗糙的文字。
现在是凌晨2:40,写完就不知道几点啦,老婆孩子0点睡了。我写程序在家是被禁止的,所以只能等老婆孩子睡熟了才能偷爬起来干。

---------------------------------------------------------------------正事开始------------------------------------------------------------------------------------
第一步,你需要最新版的OSG源代码,并编译通过,记得要编译示例程序。因为要用其中某些程序来测试修改后的操作器。
第二步,修改osgGA部分的一些代码,重新编译osgGA。
第三步,修改示例程序中的osgPick代码,把FirstPersonManipulator填进去,重新编译,用来测试修改效果。
第四步,运行osgPick,感受CS的操作体验,记得把osg的数据模型文件拷贝到与osgPick.exe同一目录。

现在开始详细的说明步骤。
打开vc2005,别的版本也可以。修改FirstPersonManipulator.cpp,将
/// Move camera right by distance parameter.
void FirstPersonManipulator::moveRight( const double distance )
{
assert( 0 && "Not implemented yet." );
}
修改为,
/// Move camera right by distance parameter.
void FirstPersonManipulator::moveRight( const double distance )
{
_eye += _rotation * Vec3d( distance, 0., 0. );
}
至于为什么,我暂时先不解释,以后的教程里会详细介绍相关的数学知识。
在FirstPersonManipulator.h文件里添加
virtual bool handleKeyDown( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us );
最好添加在protected:段落里。
在FirstPersonManipulator.cpp添加
/// Handles GUIEventAdapter::KEYDOWN event.
bool FirstPersonManipulator::handleKeyDown( const GUIEventAdapter& ea, GUIActionAdapter& us )
{
if( ea.getKey() == GUIEventAdapter::KEY_Space )
{
flushMouseEventStack();
_thrown = false;
home(ea,us);
return true;
}
if( ea.getKey() == 'w' )
{
moveForward(5.0);
return true;
}
if( ea.getKey() == 's' )
{
moveForward(-5.0);
return true;
}
if( ea.getKey() == 'a' )
{
moveRight(-5.0);
return true;
}
if( ea.getKey() == 'd' )
{
moveRight(5.0);
return true;
}
return false;

}
生成osgGA。

在osgPick的代码里添加
keyswitchManipulator->addMatrixManipulator( '5', "fps", new osgGA::FirstPersonManipulator() );
记住,在
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
这一行紧后面添加。就怕新手不会弄。
生成oskPick,运行它。可以在bin目录里直接双击osgPick.exe.
按下数字5切换至CS操作器,按下WSAD键,体会下,有没有CS的感觉。千万记住fountain.osgt要与osgPick.exe放在一起,新手急死人啊,呵呵。
如果不出差错的话,就应该能体验CS的感觉啦。
我这里是可以体验的,但是效果很差强人意,有明显的卡、顿,不流畅。

这个问题其实很简单,因为系统对handleKeyDown的调用频率并不高,所以造成不流畅。我们必须让WSAD拥有绝对的优先被处理权。
FirstPersonManipulator继承自StandardManipulator,所以要修改StandardManipulator的代码,让我们亲爱的WSAD最先被执行,有消息就执行。
为此,在StandardManipulator头文件的protected段落中添加
virtual bool DoItEveryEvent(){return true;};
然后再改动StandardManipulator.cpp
在bool StandardManipulator::handle( const GUIEventAdapter& ea, GUIActionAdapter& us )函数
一开始添加一句DoItEveryEvent();
变为下面的样子。
/** Handles events. Returns true if handled, false otherwise.*/
bool StandardManipulator::handle( const GUIEventAdapter& ea, GUIActionAdapter& us )
{
DoItEveryEvent();
switch( ea.getEventType() )
{

case GUIEventAdapter::FRAME:
return handleFrame( ea, us );

case GUIEventAdapter::RESIZE:
return handleResize( ea, us );

default:
break;
}

if( ea.getHandled() )
return false;

switch( ea.getEventType() )
{
case GUIEventAdapter::MOVE:
return handleMouseMove( ea, us );

case GUIEventAdapter::DRAG:
return handleMouseDrag( ea, us );

case GUIEventAdapter::PUSH:
return handleMousePush( ea, us );

case GUIEventAdapter::RELEASE:
return handleMouseRelease( ea, us );

case GUIEventAdapter::KEYDOWN:
return handleKeyDown( ea, us );

case GUIEventAdapter::KEYUP:
return handleKeyUp( ea, us );

case GUIEventAdapter::SCROLL:
if( _flags & PROCESS_MOUSE_WHEEL )
return handleMouseWheel( ea, us );
else
return false;

default:
return false;
}
}

其实就加了一句函数调用。为了新手方便就不计较篇幅了。
然后在
FirstPersonManipulator头文件的protected段落中添加
virtual bool DoItEveryEvent();
在FirstPersonManipulator.cpp中添加
bool FirstPersonManipulator::DoItEveryEvent()
{
if(GetKeyState('W') & 0x80)
{
moveForward(5.0);
}
if(GetKeyState('S') & 0x80)
{
moveForward(-5.0);
}
if(GetKeyState('A') & 0x80)
{
moveRight(-5.0);
}
if(GetKeyState('D') & 0x80)
{
moveRight(5.0);
}
return true;
}
把原来的handleKeyDown函数在头文件和cpp文件中注释掉,删了也行。
生成osgGA,在bin目录里双击osgPick.exe,按5,然后按WSAD试试,一切变得很顺滑,呵呵呵。

好啦,写完啦,该睡觉啦,再不睡就翘辫子啦。

sky11811 发表于 2011-9-7 03:54:05

走啦,睡啦。

Hadse 发表于 2011-9-7 08:20:06

顶起,支持。

array 发表于 2011-9-7 08:25:42

谢谢发帖共享,不过楼主为什么不考虑把自己的更改提交给osg-submissions呢,呵呵

tianxiao888 发表于 2011-9-7 11:01:50

楼主也要注意休息啊~~~~

mijue 发表于 2011-9-7 11:24:10

多谢楼主了

sky11811 发表于 2011-9-7 20:13:30

如果GetKeyState函数找不到,请加上这一句 #include <windows.h>

Roc 发表于 2011-9-8 10:48:33

是真名士自风流。

fenma3422 发表于 2011-9-13 12:24:39

楼主精神可嘉。

qele 发表于 2011-9-13 14:54:23

身体重要,还是要先休息好啊

denghua5852 发表于 2012-2-7 12:53:34

敬佩楼主的精神,向您学习,敬礼!

kebi8085454 发表于 2012-2-17 13:39:52

向LZ学习。

zombie0606 发表于 2012-7-1 17:31:41

谢谢楼主分享!

zombie0606 发表于 2012-7-1 17:31:46

谢谢楼主分享!

zombie0606 发表于 2012-7-1 17:31:54

谢谢楼主分享!

木子匕 发表于 2012-7-23 17:15:55

好东西 mark 下!话说我这水平还只是学习怎么用!还没深入到了解库里门的函数!

xuhaiyan8825 发表于 2012-8-19 11:32:58

osg的最新trunk版,实现了这个类,但是我在android上运行,没效果,不知道为什么

allen 发表于 2012-9-23 13:03:38

精神可嘉,可嘉。努力学习
页: [1]
查看完整版本: 无用教程第(二)集 sky1811