refactor: update debug state management and rendering systems

This commit is contained in:
Ryan Walters
2025-08-19 11:31:31 -05:00
parent 5109457fcd
commit 8b5e66f514
5 changed files with 90 additions and 90 deletions

View File

@@ -251,14 +251,13 @@ impl Game {
backbuffer: NonSendMut<BackbufferResource>, backbuffer: NonSendMut<BackbufferResource>,
debug_state: Res<DebugState>, debug_state: Res<DebugState>,
mut dirty: ResMut<RenderDirty>| { mut dirty: ResMut<RenderDirty>| {
if dirty.0 || *debug_state != DebugState::Off { if dirty.0 || debug_state.enabled {
// Only copy backbuffer to main canvas if debug rendering is off // Only copy backbuffer to main canvas if debug rendering is off
// (debug rendering draws directly to main canvas) // (debug rendering draws directly to main canvas)
if *debug_state == DebugState::Off { if !debug_state.enabled {
canvas.copy(&backbuffer.0, None, None).unwrap(); canvas.present();
} }
dirty.0 = false; dirty.0 = false;
canvas.present();
} }
}, },
), ),

View File

@@ -16,22 +16,13 @@ use sdl2::render::{Canvas, Texture, TextureCreator};
use sdl2::ttf::Font; use sdl2::ttf::Font;
use sdl2::video::{Window, WindowContext}; use sdl2::video::{Window, WindowContext};
#[derive(Resource, Default, Debug, Copy, Clone, PartialEq)] #[derive(Resource, Default, Debug, Copy, Clone)]
pub enum DebugState { pub struct DebugState {
#[default] pub enabled: bool,
Off,
Graph,
Collision,
} }
impl DebugState { fn f32_to_u8(value: f32) -> u8 {
pub fn next(&self) -> Self { (value * 255.0) as u8
match self {
DebugState::Off => DebugState::Graph,
DebugState::Graph => DebugState::Collision,
DebugState::Collision => DebugState::Off,
}
}
} }
/// Resource to hold the debug texture for persistent rendering /// Resource to hold the debug texture for persistent rendering
@@ -110,7 +101,7 @@ pub fn debug_render_system(
colliders: Query<(&Collider, &Position)>, colliders: Query<(&Collider, &Position)>,
cursor: Res<CursorPosition>, cursor: Res<CursorPosition>,
) { ) {
if *debug_state == DebugState::Off { if !debug_state.enabled {
return; return;
} }
let scale = let scale =
@@ -140,8 +131,6 @@ pub fn debug_render_system(
// Draw debug info on the high-resolution debug texture // Draw debug info on the high-resolution debug texture
canvas canvas
.with_texture_canvas(&mut debug_texture.0, |debug_canvas| { .with_texture_canvas(&mut debug_texture.0, |debug_canvas| {
match *debug_state {
DebugState::Graph => {
// Find the closest node to the cursor // Find the closest node to the cursor
let closest_node = if let Some(cursor_world_pos) = cursor_world_pos { let closest_node = if let Some(cursor_world_pos) = cursor_world_pos {
@@ -155,7 +144,23 @@ pub fn debug_render_system(
None None
}; };
debug_canvas.set_draw_color(Color::RED); debug_canvas.set_draw_color(Color::GREEN);
for (collider, position) in colliders.iter() {
let pos = position.get_pixel_position(&map.graph).unwrap();
// Transform position and size using common methods
let pos = (pos * scale).as_ivec2();
let size = (collider.size * scale) as u32;
let rect = Rect::from_center(Point::from((pos.x, pos.y)), size, size);
debug_canvas.draw_rect(rect).unwrap();
}
debug_canvas.set_draw_color(Color {
a: f32_to_u8(0.4),
..Color::RED
});
debug_canvas.set_blend_mode(sdl2::render::BlendMode::Blend);
for (start_node, end_node) in map.graph.edges() { for (start_node, end_node) in map.graph.edges() {
let start_node_model = map.graph.get_node(start_node).unwrap(); let start_node_model = map.graph.get_node(start_node).unwrap();
let end_node = map.graph.get_node(end_node.target).unwrap().position; let end_node = map.graph.get_node(end_node.target).unwrap().position;
@@ -173,15 +178,18 @@ pub fn debug_render_system(
let pos = node.position; let pos = node.position;
// Set color based on whether the node is the closest to the cursor // Set color based on whether the node is the closest to the cursor
debug_canvas.set_draw_color(if Some(id) == closest_node { debug_canvas.set_draw_color(Color {
a: f32_to_u8(if Some(id) == closest_node { 0.75 } else { 0.6 }),
..(if Some(id) == closest_node {
Color::YELLOW Color::YELLOW
} else { } else {
Color::BLUE Color::BLUE
})
}); });
// Transform position using common method // Transform position using common method
let pos = transform_position_with_offset(pos, scale); let pos = transform_position_with_offset(pos, scale);
let size = (3.0 * scale) as u32; let size = (2.0 * scale) as u32;
debug_canvas debug_canvas
.fill_rect(Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size)) .fill_rect(Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size))
@@ -193,27 +201,17 @@ pub fn debug_render_system(
let node = map.graph.get_node(closest_node_id).unwrap(); let node = map.graph.get_node(closest_node_id).unwrap();
let pos = transform_position_with_offset(node.position, scale); let pos = transform_position_with_offset(node.position, scale);
let surface = font.render(&closest_node_id.to_string()).blended(Color::WHITE).unwrap(); let surface = font
.render(&closest_node_id.to_string())
.blended(Color {
a: f32_to_u8(0.4),
..Color::WHITE
})
.unwrap();
let texture = texture_creator.create_texture_from_surface(&surface).unwrap(); let texture = texture_creator.create_texture_from_surface(&surface).unwrap();
let dest = Rect::new(pos.x + 10, pos.y - 5, texture.query().width, texture.query().height); let dest = Rect::new(pos.x + 10, pos.y - 5, texture.query().width, texture.query().height);
debug_canvas.copy(&texture, None, dest).unwrap(); debug_canvas.copy(&texture, None, dest).unwrap();
} }
}
DebugState::Collision => {
debug_canvas.set_draw_color(Color::GREEN);
for (collider, position) in colliders.iter() {
let pos = position.get_pixel_position(&map.graph).unwrap();
// Transform position and size using common methods
let pos = (pos * scale).as_ivec2();
let size = (collider.size * scale) as u32;
let rect = Rect::from_center(Point::from((pos.x, pos.y)), size, size);
debug_canvas.draw_rect(rect).unwrap();
}
}
_ => {}
}
// Render timing information in the top-left corner // Render timing information in the top-left corner
render_timing_display(debug_canvas, &mut texture_creator, &timings, font); render_timing_display(debug_canvas, &mut texture_creator, &timings, font);
@@ -222,4 +220,5 @@ pub fn debug_render_system(
// Draw the debug texture directly onto the main canvas at full resolution // Draw the debug texture directly onto the main canvas at full resolution
canvas.copy(&debug_texture.0, None, None).unwrap(); canvas.copy(&debug_texture.0, None, None).unwrap();
canvas.present();
} }

View File

@@ -57,7 +57,7 @@ pub fn player_control_system(
state.exit = true; state.exit = true;
} }
GameCommand::ToggleDebug => { GameCommand::ToggleDebug => {
*debug_state = debug_state.next(); debug_state.enabled = !debug_state.enabled;
} }
GameCommand::MuteAudio => { GameCommand::MuteAudio => {
audio_state.muted = !audio_state.muted; audio_state.muted = !audio_state.muted;

View File

@@ -120,4 +120,6 @@ pub fn render_system(
}) })
.err() .err()
.map(|e| errors.write(TextureError::RenderFailed(e.to_string()).into())); .map(|e| errors.write(TextureError::RenderFailed(e.to_string()).into()));
canvas.copy(&backbuffer.0, None, None).unwrap();
} }

View File

@@ -21,7 +21,7 @@ fn create_test_world() -> World {
// Add resources // Add resources
world.insert_resource(GlobalState { exit: false }); world.insert_resource(GlobalState { exit: false });
world.insert_resource(DebugState::Off); world.insert_resource(DebugState::default());
world.insert_resource(AudioState::default()); world.insert_resource(AudioState::default());
world.insert_resource(DeltaTime(1.0 / 60.0)); // 60 FPS world.insert_resource(DeltaTime(1.0 / 60.0)); // 60 FPS
world.insert_resource(Events::<GameEvent>::default()); world.insert_resource(Events::<GameEvent>::default());
@@ -222,7 +222,7 @@ fn test_player_control_system_toggle_debug() {
// Check that debug state changed // Check that debug state changed
let debug_state = world.resource::<DebugState>(); let debug_state = world.resource::<DebugState>();
assert_eq!(*debug_state, DebugState::Graph); assert_eq!(debug_state.enabled, true);
} }
#[test] #[test]
@@ -565,7 +565,7 @@ fn test_player_state_persistence_across_systems() {
let position = *query.single(&world).expect("Player should exist"); let position = *query.single(&world).expect("Player should exist");
// Check that the state changes persisted individually // Check that the state changes persisted individually
assert_eq!(debug_state_after_toggle, DebugState::Graph, "Debug state should have toggled"); assert_eq!(debug_state_after_toggle.enabled, true, "Debug state should have toggled");
assert!(audio_muted_after_toggle, "Audio should be muted"); assert!(audio_muted_after_toggle, "Audio should be muted");
// Player position depends on actual map connectivity // Player position depends on actual map connectivity