【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();
}

运行效果

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

相关推荐
山土成旧客14 小时前
【Python学习打卡-Day26】函数的艺术(上):从基础定义到参数魔法
开发语言·python·学习
车载测试工程师14 小时前
CAPL学习-AVB交互层-媒体函数1-回调&基本函数
网络·学习·tcp/ip·媒体·capl·canoe
GoldY丶14 小时前
【Geek渗透之路】小迪安全笔记——web安全(3)
笔记·安全·web安全·网络安全·安全威胁分析
richxu2025100114 小时前
嵌入式学习之路-->stm32篇-->(0)学习路线
stm32·嵌入式硬件·学习
全栈独立开发者14 小时前
[开源] 架构师手撸 Spring Boot 3.5 + UniApp 扫码点餐系统,B站演示视频首发!
笔记
丹宇码农14 小时前
使用AI一步生成音视频文件的会议纪要或者课后笔记
人工智能·笔记·音视频
xiaobuding_QAQ14 小时前
51汇编仿真proteus8.15学习篇二(附源码)
开发语言·汇编·单片机·学习·proteus
黑客思维者14 小时前
机器学习015:监督学习【分类算法】( 决策树)-- 像玩“20个问题”游戏一样做决策
学习·机器学习·分类
Larry_Yanan1 天前
Qt多进程(一)进程间通信概括
开发语言·c++·qt·学习
做cv的小昊1 天前
【TJU】信息检索与分析课程笔记和练习(1)认识文献
经验分享·笔记·学习·搜索引擎·全文检索