【OSG学习笔记】Day 13: 事件处理——响应键盘与鼠标

OpenSceneGraph (OSG) 中,事件处理是实现用户交互功能的重要部分。

通过自定义按键事件(如 WASD 键控制模型移动),可以让用户与场景进行互动。

osgGA::GUIEventHandler

osgGA::GUIEventHandlerOpenSceneGraph (OSG) 中用于处理用户输入事件(如键盘、鼠标等)的一个基类。

通过继承 osgGA::GUIEventHandler 并重写其方法,可以实现自定义的事件处理逻辑,以便对用户的交互做出响应。

创建自定义事件处理器

OSG 提供了一个基类 osgGA::GUIEventHandler,可以用来自定义事件处理逻辑。

我们需要继承这个类,并重写其 handle() 方法。

cpp 复制代码
#include <osgViewer/Viewer>
#include <osg/MatrixTransform>
#include <osgGA/GUIEventHandler>
#include <osg/PositionAttitudeTransform>

// 自定义事件处理器
class CustomKeyboardHandler : public osgGA::GUIEventHandler {
public:
    CustomKeyboardHandler(osg::ref_ptr<osg::PositionAttitudeTransform> transform)
        : _transform(transform), _moveSpeed(1.0f) {}

    // 重写 handle() 方法
    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&) override {
        switch (ea.getEventType()) {
            case osgGA::GUIEventAdapter::KEYDOWN: {
                float delta = _moveSpeed; // 移动速度
                osg::Vec3d pos = _transform->getPosition(); // 获取当前模型位置

                switch (ea.getKey()) {
                    case 'w': case 'W': // 向前移动
                        pos.z() += delta;
                        break;
                    case 's': case 'S': // 向后移动
                        pos.z() -= delta;
                        break;
                    case 'a': case 'A': // 向左移动
                        pos.x() -= delta;
                        break;
                    case 'd': case 'D': // 向右移动
                        pos.x() += delta;
                        break;
                    default:
                        return false; // 未处理的按键
                }

                _transform->setPosition(pos); // 更新模型位置
                return true; // 表示事件已处理
            }
            default:
                return false; // 其他事件未处理
        }
    }

private:
    osg::ref_ptr<osg::PositionAttitudeTransform> _transform; // 模型变换节点
    float _moveSpeed; // 移动速度
};

设置场景中的可移动模型

为了演示 WASD 控制,我们需要一个模型,并将其附加到 osg::PositionAttitudeTransform 节点上。

这个节点允许我们轻松地调整模型的位置和姿态。

cpp 复制代码
osg::ref_ptr<osg::Node> createModel() {
    // 创建一个简单的几何体作为模型(例如立方体)
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 1.0f)));
    return geode.release();
}

整合事件处理器

将自定义事件处理器添加到 OSG 的视图器中,并运行程序。

cpp 复制代码
int main() {
    // 创建视图器
    osgViewer::Viewer viewer;

    // 创建一个 PositionAttitudeTransform 节点用于控制模型位置
    osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
    transform->addChild(createModel()); // 将模型添加到变换节点

    // 将变换节点添加到场景根节点
    osg::ref_ptr<osg::Group> root = new osg::Group;
    root->addChild(transform);

    // 添加自定义事件处理器
    viewer.addEventHandler(new CustomKeyboardHandler(transform));

    // 设置场景数据
    viewer.setSceneData(root);

    // 运行视图器
    return viewer.run();
}

实战

我们来实现让我们的钢铁侠动起来的效果。

代码如下:

cpp 复制代码
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include <osgDB/ReadFile>
#include <iostream>
#include <cstdlib>

// 自定义事件处理类
class KeyHandler : public osgGA::GUIEventHandler
{
public:
    KeyHandler(osg::MatrixTransform* transform) : _transform(transform) {}

    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        switch (ea.getEventType())
        {
        case osgGA::GUIEventAdapter::KEYDOWN:
            switch (ea.getKey())
            {
            case 'w':
            case 'W':
                // 向前移动
                translateNode(osg::Vec3(0.0f, 10.0f, 0.0f));
                return true;
            case 'a':
            case 'A':
                // 向左移动
                translateNode(osg::Vec3(-10.0f, 0.0f, 0.0f));
                return true;
            case 's':
            case 'S':
                // 向后移动
                translateNode(osg::Vec3(0.0f, -10.0f, 0.0f));
                return true;
            case 'd':
            case 'D':
                // 向右移动
                translateNode(osg::Vec3(10.0f, 0.0f, 0.0f));
                return true;
            default:
                break;
            }
        default:
            break;
        }
        return false;
    }

private:
    void translateNode(const osg::Vec3& translation)
    {
        // 获取当前矩阵
        osg::Matrix matrix = _transform->getMatrix();
        // 对矩阵进行平移操作
        matrix.preMultTranslate(translation);
        // 设置新的矩阵
        _transform->setMatrix(matrix);
    }

    osg::ref_ptr<osg::MatrixTransform> _transform;
};

int main()
{
    // 创建Viewer对象
    osgViewer::Viewer viewer;

    // 创建一个MatrixTransform节点
    osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;

    // 加载模型(支持.osg/.obj格式)
    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../IronMan.osg");  // 替换为你的模型路径

    // 检查模型是否加载成功
    if (!model) {
        std::cerr << "模型加载失败!请检查路径和格式。" << std::endl;
        return 1;
    }

    // 将几何体添加到MatrixTransform节点
    transform->addChild(model);

    // 创建场景图的根节点
    osg::ref_ptr<osg::Group> root = new osg::Group;
    root->addChild(transform);

    // 设置场景数据
    viewer.setSceneData(root);

    // 创建自定义事件处理程序并添加到Viewer
    viewer.addEventHandler(new KeyHandler(transform));

    // 运行Viewer
    return viewer.run();
}

运行效果

距离做游戏又进了一步。_

相关推荐
zcyf08091 小时前
kafka理论学习汇总
java·分布式·学习·kafka
北漂老男孩1 小时前
二进制、高位低位、位移操作与进制转换全解
笔记
freexyn1 小时前
Matlab自学笔记五十二:变量名称:检查变量名称是否存在或是否与关键字冲突
人工智能·笔记·算法·matlab
*TQK*1 小时前
线性代数——行列式⭐
笔记·学习·线性代数
四夕白告木贞2 小时前
stm32week13
stm32·单片机·嵌入式硬件·学习
九亿AI算法优化工作室&2 小时前
结合大语言模型的机械臂抓取操作学习
人工智能·学习·语言模型·自然语言处理
我想吃余2 小时前
Linux学习笔记(一):Linux下的基本指令
linux·笔记·学习
njsgcs3 小时前
yolov5 源码 +jupyter notebook 笔记 kaggle
笔记·yolo·jupyter
maray3 小时前
GPU 架构入门笔记
笔记
ayas123194 小时前
数模学习:二,MATLAB的基本语法使用
学习