插件如何捕捉用户操作

一个Plugin提供了一些函数接受用户输入,在首帧之前要统计所有用户输入, 一个简单的方法是在Plugin::finish()做处理。

在生态库中很少见到这种需求,只有在复杂生态库才能看到。

在Plugin构建时添加一个保存数据的资源,在所有插件加载完毕后,读取数据并删掉资源。

impl Plugin for EnhancedInputPlugin {
    fn build(&self, app: &mut App) {
        app.init_resource::<ContextRegistry>()
            .init_resource::<ResetInput>()
            .init_resource::<ActionSources>()
            .configure_sets(PreUpdate, EnhancedInputSystem.after(InputSystem));
    }

    fn finish(&self, app: &mut App) {
        let registry = app
            .world_mut()
            .remove_resource::<ContextRegistry>()
            .expect("registry should be inserted in `build`");

        for contexts in registry.iter() {
            contexts.setup(app);
        }
    }
}

impl InputContextAppExt for App {
    fn add_input_context<C: InputContext>(&mut self) -> &mut Self {
        debug!(
            "registering `{}` for `{}`",
            any::type_name::<C>(),
            any::type_name::<C::Schedule>(),
        );

        let id = self.world_mut().register_component::<Actions<C>>();
        let mut registry = self.world_mut().resource_mut::<ContextRegistry>(); // <--
        if let Some(contexts) = registry
            .iter_mut()
            .find(|c| c.schedule_id == TypeId::of::<C::Schedule>())
        {
            debug_assert!(
                !contexts.action_ids.contains(&id),
                "context `{}` shouldn't be added more then once",
                any::type_name::<C>()
            );
            contexts.action_ids.push(id); // 保存
        } else {
            let mut contexts = ScheduleContexts::new::<C::Schedule>();
            contexts.action_ids.push(id);
            registry.push(contexts); // 保存
        }

        self.add_observer(add_context::<C>)
            .add_observer(remove_context::<C>);

        self
    }
}