bevy_egui

repository·main·Indexed 23 days ago

https://github.com/vladbat00/bevy_egui

A plugin for integrating the egui immediate-mode GUI library into the Bevy game engine, supporting desktop, web, and mobile platforms. Version 0.41.1 provides tools for managing Egui contexts, handling input events via EguiInputEvent, and implementing world-space UI. It includes features like multi-pass mode via EguiPrimaryContextPass, input consumption tracking with EguiWantsInput, and the ability to absorb Bevy input buffers.

Tokens
8.1K
Snippets
14
Records
50
Agent score
80%

What's inside bevy_egui

  1. Install bevy_egui

    main

    Add bevy_egui and bevy to your Cargo.toml dependencies.

    Linux Requirements: On Linux, you must install XCB development libraries. For Debian-based systems, run:

    sudo apt install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
    # Cargo.toml
    [dependencies]
    bevy = "0.19.0"
    bevy_egui = "0.41.1"
  2. Basic usage of bevy_egui

    main

    To use bevy_egui, add the EguiPlugin to your Bevy App. To render UI, create a system that takes EguiContexts as an argument and uses contexts.ctx_mut() to access the egui context.

    This example uses multi-pass mode by adding the UI system to the EguiPrimaryContextPass schedule. Multi-pass mode is the recommended way to use Egui with Bevy, though single-pass mode is also available (but may be deprecated).

    use bevy::prelude::*;
    use bevy_egui::{egui, EguiContexts, EguiPlugin, EguiPrimaryContextPass};
    
    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)
            .add_plugins(EguiPlugin::default())
            .add_systems(Startup, setup_camera_system)
            .add_systems(EguiPrimaryContextPass, ui_example_system)
            .run();
    }
    
    fn setup_camera_system(mut commands: Commands) {
        commands.spawn(Camera2d);
    }
    
    fn ui_example_system(mut contexts: EguiContexts) -> Result<(), EguiContexts::Error> {
        egui::Window::new("Hello").show(contexts.ctx_mut()?, |ui| {
            ui.label("world");
        });
        Ok(())
    }
  3. Run bevy_egui examples

    main

    You can run the included examples using cargo run --example <name>. Replace <name> with the name of the example you wish to run (e.g., ui, split_screen, absorb_input).

    cargo run --example ui
  4. Run Egui in multi-pass mode with EguiMultipassSchedule

    main

    For complex UI setups where you want to run specific Bevy schedules inside the Egui UI loop, use the multi-pass mode.

    1. Attach an EguiMultipassSchedule component to your Egui context entity.
    2. Ensure each context in multi-pass mode has a unique schedule.
    3. The run_egui_context_pass_loop_system will detect these components and run the provided schedule during the ctx.run_ui call.

    If no multi-pass contexts are found, the system defaults to running the EguiPrimaryContextPass schedule for primary contexts.

  5. Check if Egui wants input using EguiWantsInput

    main

    The EguiWantsInput resource tracks whether any Egui context is currently consuming input. This is useful for preventing game systems (like character movement or camera control) from reacting when the user is interacting with an Egui UI element.

    Key methods:

    • wants_any_pointer_input(): Returns true if the pointer is over an Egui area, if Egui wants pointer input (e.g., dragging a widget), if Egui is actively using the pointer, or if a popup is open.
    • wants_any_keyboard_input(): Returns true if Egui is listening to text input or if a popup is open.
    • wants_any_input(): Returns true if either pointer or keyboard input is being consumed.
  6. Configure Egui input processing via System Sets

    main

    The bevy_egui plugin uses several system sets to manage the lifecycle of input and rendering. You can use these to hook your own systems into the input pipeline.

    EguiPreUpdateSet

    Controls the initialization and input processing before the egui pass begins:

    • InitContexts: Initializes Egui contexts for new render targets.
    • ProcessInput: Reads Bevy inputs and writes them into EguiInput.
    • BeginPass: Begins the egui pass.

    EguiInputSet

    Subsets of EguiPreUpdateSet::ProcessInput for fine-grained control:

    • InitReading: Reads key modifiers and pointer positions.
    • FocusContext: Processes mouse/touch messages and updates focus.
    • ReadBevyMessages: Processes remaining messages for window/non-window contexts.
    • WriteEguiEvents: Feeds all events into EguiInput.

    To modify input, you can use: system.after(EguiPreUpdateSet::ProcessInput).before(EguiSet::BeginPass).

  7. Use `TextAgentChannel` to communicate egui events

    main

    The TextAgentChannel resource acts as a bridge between the browser's text input events and the Bevy/egui ecosystem. It uses a crossbeam_channel to send egui::Event objects.

    When the text agent receives input from the browser (via the hidden <input> element), it sends egui::Event variants (such as Text or Ime) through this channel. These events are then processed by the write_text_agent_channel_events_system to be injected into the appropriate EguiInputEvent stream for your egui contexts.

  8. Manage non-window Egui contexts (World-space UI)

    main

    If you are rendering Egui to a non-window target (e.g., a texture in world-space), bevy_egui provides resources to manage focus and hovering:

    • HoveredNonWindowEguiContext: A resource containing the entity of a non-window context currently being hovered by the pointer. Note: Users are responsible for updating this resource and the EguiContextPointerPosition component of the hovered entity during the InitReading stage.
    • FocusedNonWindowEguiContext: A resource containing the entity of a non-window context that has gained focus (e.g., via a mouse click or touch start).

    When these resources exist, input messages (like keyboard or pointer buttons) can be redirected from the primary window to these specific non-window contexts.

  9. How Egui multi-pass mode works

    main

    By default, egui supports multi-pass immediate mode. This is useful for widgets like egui::Grid that need to know the size of all columns before rendering to avoid 'first-frame jitters'.

    To enable multi-pass support for the primary context, use EguiPlugin::default() (which enables it by default). Your UI systems must then be added to the EguiPrimaryContextPass schedule.

    Manual Context Creation If you want to manage multiple contexts (e.g., for multiple windows or rendering to an image), you can disable automatic primary context creation via EguiGlobalSettings and assign custom schedules to additional contexts using EguiMultipassSchedule.

    #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
    pub struct SecondWindowContextPass;
    
    fn setup_system(
        mut commands: Commands,
        mut egui_global_settings: ResMut<EguiGlobalSettings>,
    ) {
        // Disable automatic creation of a primary context
        egui_global_settings.auto_create_primary_context = false;
    
        // Spawn primary window camera
        commands.spawn((Camera3d::default(), PrimaryEguiContext));
    
        // Spawn second window with its own Egui context and custom schedule
        let second_window_id = commands.spawn(Window::default()).id();
        commands.spawn((
            EguiMultipassSchedule::new(SecondWindowContextPass),
            Camera3d::default(),
            Camera::default(),
            RenderTarget::Window(WindowRef::Entity(second_window_id)),
        ));
    }
    #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
    pub struct SecondWindowContextPass;
    
    fn setup_system(
        mut commands: Commands,
        mut egui_global_settings: ResMut<EguiGlobalSettings>,
    ) {
        // Disable automatic creation of a primary context
        egui_global_settings.auto_create_primary_context = false;
    
        // Spawn primary window camera
        commands.spawn((Camera3d::default(), PrimaryEguiContext));
    
        // Spawn second window with its own Egui context and custom schedule
        let second_window_id = commands.spawn(Window::default()).id();
        commands.spawn((
            EguiMultipassSchedule::new(SecondWindowContextPass),
            Camera3d::default(),
            Camera::default(),
            RenderTarget::Window(WindowRef::Entity(second_window_id)),
        ));
    }
  10. Detect hovered non-window Egui contexts

    main

    When using PickableEguiContext, you can track which Egui context (that is not a standard window) is currently being hovered by monitoring the HoveredNonWindowEguiContext resource.

    This resource is automatically inserted by the handle_over_system when a pointer enters a pickable Egui mesh and is removed by handle_out_system when the pointer leaves.

  11. Absorb Bevy input using absorb_bevy_input_system

    main

    The absorb_bevy_input_system clears Bevy's input buffers (ButtonInput<MouseButton>, ButtonInput<KeyCode>, and various message buffers) when Egui is using input.

    Warning: This system assumes bevy_egui takes priority over all other plugins. Use this only if you want Egui to completely intercept and 'swallow' input so that no other systems receive it.

    To enable this, set EguiGlobalSettings::enable_absorb_bevy_input_system to true.

  12. Configure Egui rendering order and picking

    main

    When using the bevy_ui and bevy_picking features, you can control whether Egui renders above or below Bevy UI elements using UiRenderOrder.

    • UiRenderOrder::EguiAboveBevyUi: Egui is rendered on top. Sets EguiPickingOrder to 0.6.
    • UiRenderOrder::BevyUiAboveEgui: Bevy UI is rendered on top. Sets EguiPickingOrder to 0.4.

    If bevy_picking is enabled, capture_pointer_input_system will automatically capture pointer hits on Egui windows to prevent them from interacting with objects behind the UI.