You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

游戏引擎插件系统实现优化求助:现有代码简化方案探讨

Github仓库

插件系统大致工作机制说明

Plugin trait实现了build()方法,该方法会在插件加载时被调用。build()方法接收App结构体,App即应用程序核心结构。

目前我的代码实现较为繁琐,现咨询是否存在其他更优的实现方案?

pub trait Component {
    fn start(&mut self);
    fn update(&mut self);
}

pub struct App {
    runners: Vec<Box<dyn Fn(&mut App)>>,
    components: Vec<Box<dyn Component>>,
}

&mut App方案

最初,build()方法接收&mut App参数,但无法实现如下代码:

impl Plugin for WinitWSIPlugin {
    fn build(&self, app: &mut App) {
        app.set_runner(move || {
            // 此处报错
            app.open_window(...);
        });
    }
}

据我理解,编译器不允许此操作的原因是传递的App结构体引用可能会失效。

Rc<RefCell<App>>方案

后续实现中,我改为传递Rc<RefCell<App>>,但调用borrow_mut()以执行open_window(...)时出现panic,尽管我此前并未手动调用过borrow_mut()。

impl Plugin for WinitWSIPlugin {
    fn build(&self, app: Rc<RefCell<App>>) {
        app.clone().borrow().set_runner(move || {
            let AppSystem::Windowed { info } = app.borrow().system();
            let mut winit_windows = WinitWindows::default();
            let event_loop = winit::event_loop::EventLoop::new();

            /*===== 此处触发panic =====*/
            app.borrow_mut().open_window(winit_windows.create_window(
                &event_loop,
                app.borrow().id(),
                &info,
            ));
        });
    }
}

当前采用的最终版本

在App结构体中供插件使用的字段上使用Mutex,这样即使需要修改值也无需调用borrow_mut(),只需调用borrow()即可。

impl Plugin for WinitWSIPlugin {
    fn build(&self, app: Rc<RefCell<App>>) {
        app.clone().borrow().set_runner(move || {
            let AppSystem::Windowed { info } = app.borrow().system();
            let mut winit_windows = WinitWindows::default();
            let event_loop = winit::event_loop::EventLoop::new();
            app.borrow().open_window(winit_windows.create_window(
                &event_loop,
                app.borrow().id(),
                &info,
            ));

            for component in app.borrow().components().borrow_mut().iter_mut() {
                component.init(app.clone());
            }

            let app = app.clone();
            event_loop.run(move |event, _, control_flow| {
                control_flow.set_wait();

                for component in app.borrow().components().borrow_mut().iter_mut() {
                    component.update(app.clone());
                }

                match event {
                    winit::event::Event::WindowEvent {
                        window_id: _,
                        event,
                    } => match event {
                        winit::event::WindowEvent::CloseRequested => control_flow.set_exit(),
                        _ => (),
                    },
                    _ => (),
                }
            });
        });
    }
}

内容的提问来源于stack exchange,提问作者Dmitry Klementiev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 13:01:01