OGRE+CEGUI+OIS 完美解决鼠标非独占使用

最近在用Ogre+CEGUI+OIS做游戏。在开发的过程出现了种种问题,现将问题一一整理,并将解决方案释出,供同好参阅。

OIS默认鼠标占用模式是鼠标独占使用,表现为鼠标指针无法移除当前窗口。那么如果想把鼠标指针移除窗体怎么解决呢?让OIS使用鼠标协作模式啊!代码如下:

 

//创建设备

OIS::ParamList pl;

size_t windowHnd = 0;

std::ostringstream windowHndStr;

 

m_Window->getCustomAttribute(Ogre::String(”WINDOW”), &windowHnd);

windowHndStr << windowHnd;

pl.insert(std::make_pair(std::string(”WINDOW”), windowHndStr.str()));

pl.insert(std::make_pair(std::string(”w32_mouse”), std::string(”DISCL_FOREGROUND”)));

pl.insert(std::make_pair(std::string(”w32_mouse”), std::string(”DISCL_NONEXCLUSIVE”)));

m_InputManager = OIS::InputManager::createInputSystem( pl );

 

 

这下好了,鼠标可以移除当前窗体了,突然发现没对,怎么有两个鼠标指针?好嘛,我就在当前窗口隐藏掉系统的指针!代码如下:

 

ShowCursor(0); //隐藏系统鼠标指针

 

这回应该没问题了吧~~~啦啦啦,还是没对哦!鼠标定位不准确~~~~~~~~,行!那就在mouse::MouseMoved事件中把 Moved(e.state.X.rel, e.state.Y.rel)替换成Postion(e.state.X.abs, e.state.Y.abs)

 

在编译运行,矣~~~~~~咋个指针在一个很小范围内移动呢?哦,原来OIS默认宽和高是50px啊,来设置成RenderWindow的宽高即可!代码如下:

 

_mouse->getMouseState().width=_render_window->getWidth();

_mouse->getMouseState().height=_render_window->getHeight();

 

嘿嘿,这下完美了!ohmy god~~~~~~~~为什么这样对我?鼠标都移除窗体了,为什么窗体内的那个指针还要动,那我就在MouseMoved中做边界检查,对了为了防止误点,还要在mousePressed mouseReleased做边界检查,代码就不啰嗦了!~~~=

 

 

      至此OGRE+OIS+CEGUI鼠标非独占使用,完美解决!

 

---------------------------------------------------------------------------------

最近在弄SuperRacing的时候,想把游戏鼠标换成非独占模式。全屏下,独占模式还不错,但在窗口模式下就显得不习惯了。鼠标只能在窗口里面移动,不能移动到窗口外的地方,在操作上显然不太友好。于是,我google了一下"ois 非独占",看到了很多完美的解决办法。下面就说说我自己的使用方法吧!

隐藏系统鼠标:创建窗口后,就隐藏系统鼠标,不然会出现二个鼠标的现象。::ShowCursor(FALSE);

创建OIS输入设备时指定非独占:InputManager::createInputSystem()创建设备时,参数实际上是一个std::multimap<std::string,std::string>类型的变量,通过它来传入参数值。  如:  ParamList pl;
    std::ostringstream windowHndStr;
    windowHndStr <<(size_t)hwnd;     // 窗口句柄
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));       // 传入窗口句柄                              
    pl.insert(std::make_pair(std::string("w32_mouse"), "DISCL_FOREGROUND"));
    pl.insert(std::make_pair(std::string("w32_mouse"), "DISCL_NONEXCLUSIVE"));  // 设置鼠标为协作模式

    // 创建输入设备
    mInputManager = InputManager::createInputSystem( pl );
    mKeyboard = static_cast<Keyboard*>(mInputManager->createInputObject( OISKeyboard, true));
    mMouse = static_cast<Mouse*>(mInputManager->createInputObject( OISMouse,true ));

    // 设置回调
    mMouse->setEventCallback(this);
    mKeyboard->setEventCallback(this);

    // 设置鼠标移动范围,OIS默认范围为50*50
    mMouse->getMouseState().width =windowWidth;
    mMouse->getMouseState().height = windowHeight;

注入CEGUI鼠标事件:先进行边界判断,当鼠标移出窗体外的时候,OIS会把MouseEvent.state.X.abs和MouseEvent.state.Y.abs设置成最大或最小值。比如渲染窗口大小为800*600,那么当鼠标移到窗口左边时,MouseEvent.state.X.abs会等于0而不会出现负数;移到窗口右边的时候,MouseEvent.state.Y.abs的值也不会超过800。所以我们可以如下边界判断:
if( mouseEvent.state.X.abs>0 && mouseEvent.state.X.abs<windowWidth && mouseEvent.state.Y.abs>0 && mouseEvent.state.Y.abs<windowHeight )
    CEGUI::System::getSingleton().injectMousePosition( mouseEvent.state.X.abs, mouseEvent.state.Y.abs );

适应窗口大小变化:如果程序可以动态改变窗口大小(更多可以参考http://hghhe.blog.163.com/blog/static /3237756820099163237160/edit/),那么鼠标大小也要修改重新适应窗口。当窗口大小变化后,OIS只需重新调用  mMouse->getMouseState().width =windowWidth;  mMouse->getMouseState().height = windowHeight;来重新设置鼠标移动范围。当然你可能会发现游戏窗口内的鼠标位置和系统鼠标位置不一致,那就要重新设置CEGUI鼠标显示的范围了,如:mGUIRenderer->setDisplaySize(1024,768)。

全屏与窗口切换:当游戏全屏的时候,输入使用独占模式更好一些,因为鼠标就不会移出游戏界面了(比如向上移碰到最上面的QQ)。其实在全屏与窗口的切换时,我们可以把OIS设备释放再重新创建。在窗口下使用非独占模式,而在全屏下使用独占模式。

 

 

你可能感兴趣的:(OGRE+CEGUI+OIS 完美解决鼠标非独占使用)