use bevy::input_focus::tab_navigation::TabGroup; use engine::theme::ThemedText; use super::*; /// Debug UI for Tetris /// Some overlap with more general purpose debug tools, /// but built one-off because of the changse to UI in Bevy 0.17 pub struct DebugPlugin; // Debugging wish-list: // - Bounding boxes around entities // - Toggleable in UI // - Cursor at the center of the world // - Toggleable in UI // - Show current state(s) in UI impl Plugin for DebugPlugin { fn build(&self, app: &mut App) { app .init_state::() .add_systems(Startup, setup_ui) .add_systems(Update, // Logging state transitions ( log_transition::.run_if(state_changed::), log_transition::.run_if(state_changed::), log_transition::.run_if(state_changed::), )) .add_systems(Update, toggle_debug.run_if(input_just_pressed(KeyCode::F12))) .add_systems(Update, ( toggle_state_visibility::, sync_state_to_ui::, ).run_if(state_changed::) ); } } /// Tracks if the game is in debug mode #[derive(States, Default, Clone, Eq, Debug, PartialEq, Hash, Component)] pub struct DebugState(bool); impl From for DebugState { fn from(b: bool) -> Self { DebugState(b) } } impl fmt::Display for DebugState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "DebugState {}", self.0) } } /// Setup the debugger UI fn setup_ui( mut commands: Commands, ) { commands.spawn(( Node { display: Display::Flex, flex_direction: FlexDirection::Row, align_items: AlignItems::Center, justify_content: JustifyContent::Start, column_gap: px(8), ..default() }, children![ (Text::new("debugger:"), ThemedText), (toggle_switch((),), observe(checkbox_self_update), observe(debug_toggle)), ], )); commands.spawn(( Node { bottom: px(0.0), left: px(0.0), position_type: PositionType::Absolute, flex_direction: FlexDirection::Column, ..default() }, DebugState(true), children![ (Text::new("DebugState State"), SyncState::::default()), (Text::new("Loading State"), SyncState::::default()), (Text::new("Game State"), SyncState::::default()), ] )); } /// Logs all state transitions for state T fn log_transition( curr: Res>, mut prev: Local>, ) { debug_assert!(Some(curr.get().clone()) != *prev); info!("State Change:: {:?} -> {:?}", *prev, *curr); *prev = Some(curr.get().clone()); } /// Toggle the debug state when a key is pressed fn toggle_debug( curr: Res>, mut next: ResMut>, ) { next.set(DebugState(!curr.get().0)); } fn debug_toggle(event: On>, mut next_state: ResMut>) { info!("Debug State Toggled: {:?}", event.event().value); next_state.set(event.event().value.into()); }