|
本帖最后由 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试试,一切变得很顺滑,呵呵呵。
好啦,写完啦,该睡觉啦,再不睡就翘辫子啦。 |
|