响应键盘操作需要定义一个从osgGA::GUIEventHandle派生出来的类,结合自定义的回调类callBack实现对坦克模型的前进、后退,以及炮塔的旋转操作。
键盘响应类keyboardEventHandle与回调类callBack是如何通信的呢?这里我们需要在定义一个用户自定义的类,将对模型的操作的数据封装进去。
用户自定义数据类tankInputDeviceType。
tankInputDeviceType.h
#pragma once
#include <osg/Node>
#include <osgSim/DOFTransform>
#include "myFindNodeVisitor.h"
#ifdef _DEBUG
#pragma comment(lib,"osgd.lib")
#pragma comment(lib,"osgSimd.lib")
#else
#pragma comment(lib,"osg.lib")
#pragma comment(lib,"osgSim.lib")
#endif
class tankInputDeviceType
{
public:
//构造函数,传递一个结点指针,获得osgSim::DOFTransform*类型的炮塔结点指针并保存起来
tankInputDeviceType(osg::Node& node):m_forward(false),m_backward(false),m_turretLeft(false),m_turretRight(false)
{
myFindNodeVisitor findNode("turret");
node.accept(findNode);
osgSim::DOFTransform* turretNode = dynamic_cast<osgSim::DOFTransform*>(findNode.getFirst());
if (turretNode)
{
m_turretNode = turretNode;
}
else
{
std::cout<<"tankInputDeviceType::tankInputDeviceType(osg::Node& node):"<<std::endl<<"findNode failed"<<std::endl;
}
}
//重载构造函数,传递一个结点指针,获得osgSim::DOFTransform*类型的炮塔结点指针并保存起来
tankInputDeviceType(osg::Transform& node):m_forward(false),m_backward(false),m_turretLeft(false),m_turretRight(false)
{
myFindNodeVisitor findNode("turret");
node.accept(findNode);
osgSim::DOFTransform* turretNode = dynamic_cast<osgSim::DOFTransform*>(findNode.getFirst());
if (turretNode)
{
m_turretNode = turretNode;
}
else
{
std::cout<<"tankInputDeviceType::tankInputDeviceType(osg::Node& node):"<<std::endl<<"findNode failed"<<std::endl;
}
}
//对于坦克的前进、后退,炮塔的左旋转、右旋转的设置
inline void setForward(bool b){m_forward = b;m_backward = false;}
inline void setBackward(bool b){m_backward = b;m_forward = false;}
inline void setTurretLeft(bool b){m_turretLeft = b;m_backward = false;}
inline void setTurretRight(bool b){m_turretRight = b;m_turretLeft = false;}
inline bool getForward(){return m_forward;}
inline bool getBackward(){return m_backward;}
inline bool getTurretLeft(){return m_turretLeft;}
inline bool getTurretRight(){return m_turretRight;}
inline osgSim::DOFTransform* getTurretNode(){return m_turretNode;}
protected:
bool m_forward;
bool m_backward;
bool m_turretLeft;
bool m_turretRight;
osgSim::DOFTransform* m_turretNode;
};
这里的“myFindNodeVisitor.h”在《DOF和MultiSwitch的使用》这篇博客中有源代码,这里就不赘述了。
keyboardEventHandle.h
#pragma once
#include <osgGA/GUIEventHandler>
#include "tankInputDeviceType.h"
#ifdef _DEBUG
#pragma comment(lib,"osgGAd.lib")
#else
#pragma comment(lib,"osgGA.lib")
#endif
class keyboardEventHandle:public osgGA::GUIEventHandler
{
public:
// 构造函数,初始化m_tankInputDeviceData数据成员
keyboardEventHandle(tankInputDeviceType* tankInputDeviceData):m_tankInputDeviceData(tankInputDeviceData){}
//重载handle函数,使其响应键盘事件
virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa);
protected:
tankInputDeviceType* m_tankInputDeviceData;
};
bool keyboardEventHandle::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
switch(ea.getKey())
{
case 'w':
m_tankInputDeviceData->setForward(true);
return true;
case 's':
m_tankInputDeviceData->setBackward(true);
return true;
case 'q':
m_tankInputDeviceData->setTurretLeft(true);
return true;
case 'e':
m_tankInputDeviceData->setTurretRight(true);
return true;
default:
return false;
}
}
case osgGA::GUIEventAdapter::KEYUP:
{
switch(ea.getKey())
{
case 'w':
m_tankInputDeviceData->setForward(false);
return true;
case 's':
m_tankInputDeviceData->setBackward(false);
return true;
case 'q':
m_tankInputDeviceData->setTurretLeft(false);
return true;
case 'e':
m_tankInputDeviceData->setTurretRight(false);
return true;
default:
return false;
}
}
default:
return false;
}
}
回调类tankCallBack
tankCallBack.h
#pragma once
#include <osg/NodeCallback>
#include <osg/PositionAttitudeTransform>
#include "tankInputDeviceType.h"
#ifdef _DEBUG
#pragma comment(lib,"osgd.lib")
#else
#pragma comment(lib,"osg.lib")
#endif
class tankCallBack:public osg::NodeCallback
{
public:
tankCallBack(tankInputDeviceType *tankInputData):m_tankInputData(tankInputData){}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
//模型前进
if (m_tankInputData->getForward())
{
osg::PositionAttitudeTransform* pos = dynamic_cast<osg::PositionAttitudeTransform*>(node);
if (pos)
{
tankPos = pos->getPosition();
tankPos += osg::Vec3(0.0f,0.01f,0.0f);
pos->setPosition(tankPos);
}
}
//后退
if (m_tankInputData->getBackward())
{
osg::PositionAttitudeTransform* pos = dynamic_cast<osg::PositionAttitudeTransform*>(node);
if (pos)
{
tankPos = pos->getPosition();
tankPos -= osg::Vec3(0.0f,0.01f,0.0f);
pos->setPosition(tankPos);
}
}
//炮塔左旋转
if (m_tankInputData->getTurretLeft())
{
tankRot = m_tankInputData->getTurretNode()->getCurrentHPR();
tankRot += osg::Vec3(0.001f,0,0);
m_tankInputData->getTurretNode()->setCurrentHPR(tankRot);
}
//炮塔右旋转
if (m_tankInputData->getTurretRight())
{
tankRot = m_tankInputData->getTurretNode()->getCurrentHPR();
tankRot -= osg::Vec3(0.001f,0,0);
m_tankInputData->getTurretNode()->setCurrentHPR(tankRot);
}
traverse(node,nv);
}
protected:
tankInputDeviceType* m_tankInputData;
osg::Vec3 tankRot;
osg::Vec3 tankPos;
};
main.cpp
#include "tankCallBack.h"
#include "tankInputDeviceType.h"
#include "keyboardEventHandle.h"
#include <osgDB/readfile>
#include <osgViewer/Viewer>
#include <osg/Group>
#include <osg/Node>
#include <osg/PositionAttitudeTransform>
#include <iostream>
#ifdef _DEBUG
#pragma comment(lib,"osgd.lib")
#pragma comment(lib,"osgDBd.lib")
#pragma comment(lib,"osgViewerd.lib")
#else
#pragma comment(lib,"osg.lib")
#pragma comment(lib,"osgDB.lib")
#pragma commnet(lib,"osgViewer.lib")
#endif
int main()
{
//载入坦克模型和地形模型
osg::ref_ptr<osg::Group> root = new osg::Group;
osg::ref_ptr<osg::Node> tank = osgDB::readNodeFile("/T72-tank/t72-tank_des.flt");
osg::ref_ptr<osg::Node> land = osgDB::readNodeFile("/T72-tank/JoeDirt.flt");
if (!land.get())
{
std::cout<<"land node load error"<<std::endl;
return -1;
}
if (!tank.get())
{
std::cout<<"tank node load error"<<std::endl;
return -1;
}
osg::PositionAttitudeTransform* tankPos = new osg::PositionAttitudeTransform;
tankPos->setPosition(osg::Vec3(10,10,8));
tankPos->addChild(tank.get());
root->addChild(land.get());
root->addChild(tankPos);
//声明用户自定义数据类实例,用这个类对象分别初始化回调类和键盘响应类
tankInputDeviceType* tankData = new tankInputDeviceType(*tankPos);
keyboardEventHandle* keyEH = new keyboardEventHandle(tankData);
tankCallBack* callBack = new tankCallBack(tankData);
//安装回调类
tankPos->setUpdateCallback(callBack);
//循环仿真
osgViewer::Viewer myViewer;
myViewer.addEventHandler(keyEH);
myViewer.setSceneData(root.get());
myViewer.realize();
myViewer.run();
}
移动前和炮塔为旋转
移动加炮塔旋转。