基于Delta3D的walk运动模式实现

来源:互联网 发布:淘宝网,挂烫机加热器 编辑:程序博客网 时间:2024/06/06 21:40

这是一个课设。网上关于Delta3D的资料不算多,分享一下,算是做一点微小的工作。

本例程实现坦克在平地的加减速,并配音。大体来说下面两个视频讲得很好了,不过他的方式实现的坦克转向是瞬间转的,对开发来说好处不少,不过不太符合实际,这里简单描述一下基于Walk运动模式的实现方法。完全没基础的盆友先看视频,不然下面看不懂。

https://v.qq.com/x/page/s0357t9b3n1.html

https://v.qq.com/x/page/f036009i9h9.html


先说明一下,Walk模式带来了平滑的转弯,但我没有做碰撞检测,所以这个demo中坦克是在一个无限平面上面走。下面代码中的英文是我写代码时的注释,中文是本文添加的注释。



==============================一下两段为bug说明,看完代码再回头看,不想看就不看==============================

另外有个待解决的bug。这个Walk模式采用了KeyPressed()和KeyReleased()函数来监听按键,但实际上键盘输入的连击是存在打断的情况的,比如先按住前进,键盘连击不断输入前进信号,这时我们可以通过KeyPressed()来得知这些输入。但如果我们接着点击一下其它按键(如方向左键),前进的连击就会被打断,于是KeyPressed()函数就无法再被调用,也就无法再在函数里播放音效,引擎声随后停止。

解决这个bug的方法是使用多线程,因为坦克启动后的enabled属性是恒为true的,使用另一个线程调用model->GetEnabled()方法,监听其返回值,为true即坦克在运动,后播放音效即可。即不在KeyPressed()中播放音效,而是另起线程来播放。思路大致是这样,我并没有在下面代码中修正这个bug。

=======================================================================================================


下面开始正题。

首先配置好环境,场景模型的加载是一样的。设计好App类的成员

private:RefPtr<Object> flatdirt;//地形RefPtr<Object> brdm;//坦克RefPtr<dtCore::WalkMotionModel> model;//行走模式Sound* _sound;//引擎声音,这里加/减/匀/速均使用同一个声音float speed;//坦克运动速度

下面在App类中重写Config()函数,初始化,绑定walk模式到坦克。

virtual void Config(){Application::Config();//Add tankbrdm = new Object("brdm");brdm->LoadFile("../module/brdm.ive");AddDrawable(brdm.get());speed = 6.0f;//坦克初始速度//Add mapflatdirt = new Object("flatdirt");flatdirt->LoadFile("../module/flatdirt.ive");AddDrawable(flatdirt.get());//Set tank positionosg::Vec3 brdmPosition(0.0f,-25.0f,0.0f);osg::Vec3 brdmRotation(0.0f,0.0f,0.0f);dtCore::Transform trans;trans.SetTranslation(brdmPosition);trans.SetRotation(brdmRotation);brdm->SetTransform(trans);//Set cameradtCore::Transform camPos;osg::Vec3 canXYZ(0.0f,-100.0f,35.0f);osg::Vec3 lookAtXYZ(brdmPosition);osg::Vec3 upVec(0.0f,0.0f,1.0f);camPos.Set(canXYZ,lookAtXYZ,upVec);GetCamera()->SetTransform(camPos);//Basic walk modemodel = new WalkMotionModel(GetKeyboard(),GetMouse());//在这里初始化运动模式,允许键/鼠控制,不需要的话对应参数改为0SetWalkMode(brdm,speed);//把绑定和速度封装到此方法中,方便在加减速中调用model->SetEnabled(false);//先禁用model的运动,有前进/后退键输入时方启用,避免静止时左右转的情况cout<<"Congif finished, walk speed="<<model->GetMaximumWalkSpeed()<<endl;//config结束,在控制台提示} 


上面用到了SetWalkMode()方法,下面定义:

void SetWalkMode(RefPtr<Object> obj ,float _speed){model->SetTarget(obj);//绑定对象(坦克对象)model->SetMaximumWalkSpeed(_speed);//设置坦克前进速度}

至此,坦克已经可以在场景中作匀速运动(当然,还要先执行model->SetEnabled(true);)。

下面实现加减速和音频的播放。调速逻辑是:坦克必须先启动,后方可加减速。启动后坦克以怠速6.0f运动,按住左Ctrl加速,后按住左Shift可减速(有最高/最低速度限制)。加减速键一旦释放则马上停止加减速,保持当前速度运动。一旦前进/后退被释放,坦克马上静止,速度属性回到怠速,引擎声音停止。再次启动时重新以怠速匀速前进。


于是需要设置函数监听按键的按下、抬起,并获取指定按键状态,delta3D已经封装好了函数,我们需要稍作重写。首先是按键按下的监听:

virtual bool KeyPressed(const Keyboard* keyboard, int kc){//有方向键按下if(keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Up)||keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Down)||keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Left)||keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Right)){if(!_sound->IsPlaying() && model->IsEnabled()){//音效未播放且车在运动,则播放音效_sound->Play();}}//Must start moving firstif(keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Up)||keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Down)){model->SetEnabled(true);//前进或后退已被按下,允许坦克启动
//左Ctrl加速,最大速度30.0f
if(keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Control_L)){//if(kc==osgGA::GUIEventAdapter::KEY_Control_L){if(speed<30.0f){speed += 0.5f;SetWalkMode(brdm,speed);}}//左Shift减速,最小速度6.0fif(keyboard->GetKeyState(osgGA::GUIEventAdapter::KEY_Shift_L)){//if(kc==osgGA::GUIEventAdapter::KEY_Shift_L){if(speed>6.0f){speed -= 0.5f;SetWalkMode(brdm,speed);}}return true;}//Any other button is pressedelse {return false;}

接下来监听按键抬起事件:

virtual bool KeyReleased(const Keyboard* keyboard,int kr){if(kr==osgGA::GUIEventAdapter::KEY_Up||kr==osgGA::GUIEventAdapter::KEY_Down){model->SetEnabled(false);if(_sound->IsPlaying()){_sound->Stop();//停止音效}speed=6.0f;SetWalkMode(brdm,speed);//回到怠速}return true;}


当然,我们的音效还没有初始化,也没有设计好释放逻辑。在App的构造和析构函数中进行这些任务:

App(){//Sound initAudioManager::Instantiate();AudioManager::GetInstance().LoadFile("../Image.wav");_sound=AudioManager::GetInstance().NewSound();_sound->LoadFile("../Image.wav");}~App(){AudioManager::GetInstance().FreeSound(_sound);AudioManager::Destroy();}

最好在main()函数中启动场景即可
int main(){App app;app.Config();app.Run();return 0;}

完整代码见我的github:pigcage的github

0 0
原创粉丝点击