From 43a3bdab3ef9d0e84dd144b7e9028ab2bbc50bdd Mon Sep 17 00:00:00 2001 From: "Elijah C. Voigt" Date: Tue, 11 Jun 2024 15:09:14 -0700 Subject: [PATCH] Some basic editor window boilerplate For some reson the 'input_just_pressed' condition does not behave as expected... --- examples/text_image.rs | 7 ++-- src/editor.rs | 84 ++++++++++++++++++++++++++++++++++++++++++ src/game/dice.rs | 1 - src/main.rs | 39 +++++++++++++++++++- src/prelude.rs | 4 ++ src/window.rs | 1 + 6 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 src/editor.rs create mode 100644 src/window.rs diff --git a/examples/text_image.rs b/examples/text_image.rs index 5203ed7..398c8fd 100644 --- a/examples/text_image.rs +++ b/examples/text_image.rs @@ -1,13 +1,12 @@ use std::f32::consts::PI; use bevy::{ - prelude::*, - render::{ + input::common_conditions::input_just_pressed, prelude::*, render::{ camera::RenderTarget, render_resource::{ Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, }, - }, + } }; fn main() { @@ -17,7 +16,7 @@ fn main() { .add_systems( Update, rotate_mesh - .run_if(|keys: Res>| -> bool { keys.pressed(KeyCode::Space) }), + .run_if(input_just_pressed(KeyCode::Space)), ) .run(); } diff --git a/src/editor.rs b/src/editor.rs new file mode 100644 index 0000000..1869d6a --- /dev/null +++ b/src/editor.rs @@ -0,0 +1,84 @@ +use crate::prelude::*; + +/// Menu Plugin; empty struct for Plugin impl +pub(crate) struct EditorPlugin; + +impl Plugin for EditorPlugin { + fn build(&self, app: &mut App) { + app.init_state::(); + app.add_systems(Startup, init_editor); + app.add_systems(Update, toggle_editor.run_if(input_just_pressed(KeyCode::F3))); + app.add_systems(OnEnter(EditorState::Open), open_editor); + app.add_systems(OnExit(EditorState::Open), close_editor); + } +} + +/// State tracking if the editor is open +#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default, Component)] +enum EditorState { + #[default] + Closed, + Open, +} + +#[derive(Component)] +struct Editor; + +/// Spawns all base editor entities including window, camera, and UI elements +fn init_editor( + mut commands: Commands +) { + // Spawn root editor entity hierarchy + commands.spawn(SpatialBundle { ..default() }) + .with_children(|parent| { + + let editor_window = parent.spawn(( + Editor, + Window { + title: "Editor".into(), + name: Some("Editor".into()), + visible: false, + ..default() + }, + )).id(); + + // Spawn editor camera + let _editor_camera = parent.spawn(( + Editor, + Camera3dBundle { + camera: Camera { + target: RenderTarget::Window(WindowRef::Entity(editor_window)), + ..default() + }, + ..default() + }, + )).id(); + }); +} + +fn open_editor( + mut ws: Query<&mut Window, With>, +) { + ws.iter_mut().for_each(|mut w| { + w.visible = true; + }); +} + +fn close_editor( + mut ws: Query<&mut Window, With>, +) { + ws.iter_mut().for_each(|mut w| { + w.visible = false; + }); +} + +fn toggle_editor( + state: Res>, + mut next_state: ResMut>, +) { + info!("Toggling editor on/off"); + match state.get() { + EditorState::Open => next_state.set(EditorState::Closed), + EditorState::Closed => next_state.set(EditorState::Open), + } +} \ No newline at end of file diff --git a/src/game/dice.rs b/src/game/dice.rs index 1fe86e8..36054b7 100644 --- a/src/game/dice.rs +++ b/src/game/dice.rs @@ -158,7 +158,6 @@ fn move_die( } _ => (), } - info!("Moved die {:?}", t.translation); }); } _ => (), diff --git a/src/main.rs b/src/main.rs index 7c1fd6a..6a7018c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,17 +16,32 @@ pub(crate) mod ecs; /// Imports used across the project pub(crate) mod prelude; +/// Different game modes pub(crate) mod game; +/// Debugger/Editor for inspecting the game +pub(crate) mod editor; + use crate::prelude::*; fn main() { let mut app = App::new(); - app.add_plugins(bevy::DefaultPlugins.set(low_latency_window_plugin())); + app.add_plugins(bevy::DefaultPlugins + .set(low_latency_window_plugin()) + .set(WindowPlugin { + exit_condition: ExitCondition::OnPrimaryClosed, + close_when_requested: false, + ..default() + }) + ); app.add_plugins(bevy_mod_picking::DefaultPickingPlugins); app.add_plugins(menu::MenuPlugin); app.add_plugins(ui::UiPlugin); app.add_plugins(game::GamePlugin); + app.add_plugins(editor::EditorPlugin); + app.add_systems(Update, + handle_window_close.run_if(on_event::()) + ); app.run(); } @@ -43,3 +58,25 @@ pub(crate) fn manage_visibility( } }); } + +/// When the primary window is requested to close, do so (exiting the game). +/// When a non-primary window is closed, just hide it instead of actually closing +fn handle_window_close( + mut events: EventReader, + primary: Query>, + mut secondary: Query<&mut Window, Without>, + mut commands: Commands, +) { + events.read().for_each(|WindowCloseRequested { window }| { + if primary.contains(*window) { + commands.entity(*window).remove::(); + } else { + secondary + .get_mut(*window) + .iter_mut() + .for_each(|w| { + w.visible = false; + }); + } + }); +} \ No newline at end of file diff --git a/src/prelude.rs b/src/prelude.rs index 1f0d07f..6a50409 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,6 +9,10 @@ pub(crate) use bevy::render::camera::RenderTarget; pub(crate) use bevy::render::render_resource::{ Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, }; +pub(crate) use bevy::window::WindowRef; +pub(crate) use bevy::input::common_conditions::input_just_pressed; +pub(crate) use bevy::window::{PrimaryWindow, WindowCloseRequested}; +pub(crate) use bevy::window::ExitCondition; /// Bevy Plugins pub(crate) use bevy_mod_picking::prelude::*; diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 0000000..872b855 --- /dev/null +++ b/src/window.rs @@ -0,0 +1 @@ +// TODO: window management in this file \ No newline at end of file