Skip to content

Commit

Permalink
ui: add gizmos, flatten app module (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
philiplinden authored Nov 28, 2024
1 parent 2db5450 commit 119dade
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 136 deletions.
47 changes: 47 additions & 0 deletions docs/devlog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,52 @@
# development log

## 2024-11-27

Some of my dependencies may now have Bevy 0.15 support.

- [x] avian3d: (Jondolf/avian:main)[https://github.com/Jondolf/avian/tree/main]
- [ ] bevy_heavy: not supported yet
- [x] iyes_perf_ui:
(JohnathanFL/iyes_perf_ui:main)[https://github.com/JohnathanFL/iyes_perf_ui/tree/main]
([this is open PR from a fork](https://github.com/IyesGames/iyes_perf_ui/pull/22))
- [x] iyes_progress: `0.13.0-rc.1`
- [x] bevy-trait-query:
[JoJoJet/bevy-trait-query:bevy-0.15-rc](https://github.com/JoJoJet/bevy-trait-query/tree/bevy-0.15-rc)
(sort of supported, last updated for `bevy-0.15.0-rc.2`)
- [ ] bevy-inspector-egui: not supported yet

Here are some recent projects that I might be able to steal from:

- [bevy-motion-matching](https://github.com/kahboon0425/bevy_motion_matching) -
angular velocity debug gizmos and egui UI examples for plotting
- [siege](https://github.com/xenon615/siege) - rope example in Avian3d
- [bevy-logging](https://bevy-logging.github.io/) - advanced debug logging &
tracing example/tutorial

Now that the forces are working and look reasonable, I can start working on the
flight dynamics. I need to start by adding a way to speed up and slow down the
simulation time, because a real flight takes hours. Next I need to add plots so
I can monitor and validate the simulation results for things like altitude,
temperature, and pressure.

- [ ] Physics time multiplier.
- [ ] Plotting gas properties.
- [ ] Plotting balloon kinematics.

Bonus:

- [ ] Add a payload hanging from a tether.
- [ ] Camera follow the balloon, and maybe a scale or some reference in the
background to illustrate the balloon's size and altitude.

Stretch:

- [ ] Calculate drag forces and moments on arbitrary shapes.
- [ ] Add a wind field.

I figured out how to toggle the physics gizmos at runtime and added force gizmos
that I made myself.

## 2024-11-26

I added a `GasMonitor` to the UI for displaying the gas properties in real time.
Expand Down
20 changes: 10 additions & 10 deletions src/app3d/controls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ pub struct CameraControls {

#[derive(Reflect)]
pub struct DebugControls {
pub toggle_inspector: KeyCode,
pub toggle_wireframe: KeyCode,
pub toggle_physics_debug: KeyCode,
pub toggle_perf_ui: KeyCode,
pub toggle_anything_else: KeyCode,
pub toggle_1: KeyCode,
pub toggle_2: KeyCode,
pub toggle_3: KeyCode,
pub toggle_4: KeyCode,
pub toggle_5: KeyCode,
}

#[derive(Reflect)]
Expand All @@ -55,11 +55,11 @@ impl Default for CameraControls {
impl Default for DebugControls {
fn default() -> Self {
Self {
toggle_wireframe: KeyCode::F1,
toggle_inspector: KeyCode::F2,
toggle_physics_debug: KeyCode::F3,
toggle_perf_ui: KeyCode::F4,
toggle_anything_else: KeyCode::F5,
toggle_1: KeyCode::F1,
toggle_2: KeyCode::F2,
toggle_3: KeyCode::F3,
toggle_4: KeyCode::F4,
toggle_5: KeyCode::F5,
}
}
}
Expand Down
103 changes: 54 additions & 49 deletions src/app3d/ui/dev_tools.rs → src/app3d/dev_tools.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Development tools for the game. This plugin is only enabled in dev builds.
use avian3d::debug_render::PhysicsDebugPlugin;
use avian3d::debug_render::*;
#[cfg(not(target_arch = "wasm32"))]
use bevy::pbr::wireframe::{WireframeConfig, WireframePlugin};
#[allow(unused_imports)]
Expand All @@ -13,13 +13,15 @@ use bevy::{
input::common_conditions::input_just_pressed,
prelude::*,
};
use iyes_perf_ui::prelude::*;

use crate::{app3d::controls::KeyBindingsConfig, simulator::SimState};

pub(super) fn plugin(app: &mut App) {
// Toggle the debug overlay for UI.
app.add_plugins((
pub struct DevToolsPlugin;

impl Plugin for DevToolsPlugin {
fn build(&self, app: &mut App) {
// Toggle the debug overlay for UI.
app.add_plugins((
// physics
PhysicsDebugPlugin::default(),
// performance
Expand All @@ -31,12 +33,9 @@ pub(super) fn plugin(app: &mut App) {
));

app.init_resource::<DebugState>();
app.add_event::<SpawnPerfUi>();
app.add_event::<DespawnPerfUi>();
app.add_observer(spawn_perf_ui);
app.add_observer(despawn_perf_ui);

app.add_systems(Update, log_transitions::<SimState>);
app.add_systems(Update, show_physics_gizmos);

// Wireframe doesn't work on WASM
#[cfg(not(target_arch = "wasm32"))]
Expand All @@ -46,13 +45,39 @@ pub(super) fn plugin(app: &mut App) {
// use bevy_inspector_egui::quick::WorldInspectorPlugin;
// app.add_plugins(WorldInspectorPlugin::new());
// }
}
}

#[derive(Debug, Default, Resource)]
#[derive(Debug, Resource)]
struct DebugState {
wireframe: bool,
physics_debug: bool,
perf_ui: bool,
forces: bool,
physics: bool,
}

impl Default for DebugState {
fn default() -> Self {
Self {
wireframe: false,
forces: true,
physics: false,
}
}
}

impl DebugState {
fn toggle_wireframe(&mut self) {
self.wireframe = !self.wireframe;
warn!("wireframe debug: {}", self.wireframe);
}
fn toggle_forces(&mut self) {
self.forces = !self.forces;
warn!("forces debug: {}", self.forces);
}
fn toggle_physics(&mut self) {
self.physics = !self.physics;
warn!("physics debug: {}", self.physics);
}
}

#[allow(dead_code)]
Expand All @@ -61,53 +86,33 @@ struct DebugUi;

#[cfg(not(target_arch = "wasm32"))]
fn toggle_debug_ui(
mut commands: Commands,
mut wireframe_config: ResMut<WireframeConfig>,
mut debug_state: ResMut<DebugState>,
key_input: Res<ButtonInput<KeyCode>>,
key_bindings: Res<KeyBindingsConfig>,
) {
if key_input.just_pressed(key_bindings.debug_controls.toggle_wireframe) {
debug_state.wireframe = !debug_state.wireframe;
if key_input.just_pressed(key_bindings.debug_controls.toggle_1) {
debug_state.toggle_wireframe();
wireframe_config.global = !wireframe_config.global;
warn!("wireframe: {}", debug_state.wireframe);
}

if key_input.just_pressed(key_bindings.debug_controls.toggle_physics_debug) {
debug_state.physics_debug = !debug_state.physics_debug;
warn!("physics debug: {} - not implemented", debug_state.physics_debug);
if key_input.just_pressed(key_bindings.debug_controls.toggle_2) {
debug_state.toggle_forces();
}

if key_input.just_pressed(key_bindings.debug_controls.toggle_perf_ui) {
debug_state.perf_ui = !debug_state.perf_ui;
warn!("perf ui: {}", debug_state.perf_ui);
if debug_state.perf_ui {
commands.trigger(SpawnPerfUi);
} else {
commands.trigger(DespawnPerfUi);
}
if key_input.just_pressed(key_bindings.debug_controls.toggle_3) {
debug_state.toggle_physics();
}
}

#[derive(Event, Default)]
struct SpawnPerfUi;

fn spawn_perf_ui(_trigger: Trigger<SpawnPerfUi>, mut commands: Commands) {
info!("spawn_perf_ui");
warn!("spawning perf ui DOES NOT WORK");
commands.spawn((DebugUi,
PerfUiRoot::default(),
PerfUiEntryFPS::default(),
PerfUiEntryClock::default(),
));
}

#[derive(Event, Default)]
struct DespawnPerfUi;

fn despawn_perf_ui(_trigger: Trigger<DespawnPerfUi>, mut commands: Commands, ui: Query<Entity, (With<DebugUi>, With<PerfUiRoot>)>) {
info!("despawn_perf_ui");
for ui in ui.iter() {
commands.entity(ui).despawn_recursive();
fn show_physics_gizmos(
debug_state: Res<DebugState>,
mut gizmo_store: ResMut<GizmoConfigStore>
) {
if gizmo_store.is_changed() {
let (_, physics_config) = gizmo_store.config_mut::<PhysicsGizmos>();
if debug_state.physics {
*physics_config = PhysicsGizmos::all();
} else {
*physics_config = PhysicsGizmos::none();
}
}
}
24 changes: 24 additions & 0 deletions src/app3d/gizmos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use bevy::{color::palettes::basic::*, prelude::*};

use crate::simulator::{forces::Force, SimState};

Check failure on line 3 in src/app3d/gizmos.rs

View workflow job for this annotation

GitHub Actions / build

unused import: `SimState`

const ARROW_SCALE: f32 = 0.1;

pub struct ForceArrowsPlugin;

impl Plugin for ForceArrowsPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PostUpdate, force_arrows);
}
}

fn force_arrows(query: Query<&dyn Force>, mut gizmos: Gizmos) {
for forces in query.iter() {
for force in forces.iter() {
let start = force.point_of_application();
let end = start + force.force() * ARROW_SCALE;
let color = force.color().unwrap_or(RED.into());
gizmos.arrow(start, end, color).with_tip_length(0.1);
}
}
}
56 changes: 50 additions & 6 deletions src/app3d/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
mod scene;
mod camera;
mod ui;
pub mod controls;
mod gizmos;
mod scene;
mod dev_tools;
mod monitors;

use scene::ScenePlugin;
use ui::InterfacePlugin;
use controls::ControlsPlugin;
use camera::CameraPlugin;
use controls::{ControlsPlugin, KeyBindingsConfig};
use gizmos::ForceArrowsPlugin;
use scene::ScenePlugin;
use dev_tools::DevToolsPlugin;
use monitors::MonitorsPlugin;

use bevy::app::{PluginGroup, PluginGroupBuilder};
use bevy::{app::{PluginGroup, PluginGroupBuilder}, prelude::*};

use crate::simulator::SimState;

pub struct App3dPlugins;

Expand All @@ -21,3 +27,41 @@ impl PluginGroup for App3dPlugins {
.add(CameraPlugin)
}
}

/// A plugin group that includes all interface-related plugins
pub struct InterfacePlugin;

impl Plugin for InterfacePlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
PausePlayPlugin,
ForceArrowsPlugin,
MonitorsPlugin,
#[cfg(feature = "dev")]
DevToolsPlugin,
));
}
}

pub struct PausePlayPlugin;

impl Plugin for PausePlayPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, toggle_pause);
}
}

fn toggle_pause(
sim_state: Res<State<SimState>>,
mut next_state: ResMut<NextState<SimState>>,
key_input: Res<ButtonInput<KeyCode>>,
key_bindings: Res<KeyBindingsConfig>,
) {
if key_input.just_pressed(key_bindings.time_controls.toggle_pause) {
match sim_state.as_ref().get() {
SimState::Stopped => next_state.set(SimState::Running),
SimState::Running => next_state.set(SimState::Stopped),
_ => next_state.set(SimState::Running)
}
}
}
6 changes: 3 additions & 3 deletions src/app3d/ui/monitors.rs → src/app3d/monitors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ impl PerfUiEntry for SimStateMonitor {

fn format_value(&self, value: &Self::Value) -> String {
match value {
SimState::Loading => String::from("Loading"),
SimState::Running => String::from("Running"),
SimState::Stopped => String::from("Stopped"),
_ => String::from("Unknown"),
}
}

Expand Down Expand Up @@ -118,8 +118,8 @@ impl PerfUiEntry for SimStateMonitor {
fn value_color(&self, value: &Self::Value) -> Option<Color> {
match *value {
SimState::Running => self.color_gradient.get_color_for_value(0.0),
SimState::Stopped => self.color_gradient.get_color_for_value(10.0),
_ => self.color_gradient.get_color_for_value(5.0),
SimState::Stopped => self.color_gradient.get_color_for_value(5.0),
_ => self.color_gradient.get_color_for_value(10.0),
}
}

Expand Down
Loading

0 comments on commit 119dade

Please sign in to comment.