Compare commits

..

3 Commits

Author SHA1 Message Date
Ryan Walters
9624bcf359 feat: collision helper, ghost/pacman collision events, collision tests
minor format updates from copilot's commit
2025-08-27 22:26:49 -05:00
Copilot
67a5c4a1ed Remove 9 redundant and non-valuable tests to improve test suite quality (#4)
* Initial plan

* Remove 9 redundant and non-valuable tests across events, formatting, and item modules

Co-authored-by: Xevion <44609630+Xevion@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Xevion <44609630+Xevion@users.noreply.github.com>
2025-08-19 13:07:14 -05:00
Ryan Walters
8b5e66f514 refactor: update debug state management and rendering systems 2025-08-19 11:31:31 -05:00
11 changed files with 296 additions and 229 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

@@ -6,9 +6,28 @@ use bevy_ecs::system::{Query, Res};
use crate::error::GameError; use crate::error::GameError;
use crate::events::GameEvent; use crate::events::GameEvent;
use crate::map::builder::Map; use crate::map::builder::Map;
use crate::systems::components::{Collider, ItemCollider, PacmanCollider}; use crate::systems::components::{Collider, GhostCollider, ItemCollider, PacmanCollider};
use crate::systems::movement::Position; use crate::systems::movement::Position;
/// Helper function to check collision between two entities with colliders.
pub fn check_collision(
pos1: &Position,
collider1: &Collider,
pos2: &Position,
collider2: &Collider,
map: &Map,
) -> Result<bool, GameError> {
let pixel1 = pos1
.get_pixel_position(&map.graph)
.map_err(|e| GameError::InvalidState(format!("Failed to get pixel position for entity 1: {}", e)))?;
let pixel2 = pos2
.get_pixel_position(&map.graph)
.map_err(|e| GameError::InvalidState(format!("Failed to get pixel position for entity 2: {}", e)))?;
let distance = pixel1.distance(pixel2);
Ok(collider1.collides_with(collider2.size, distance))
}
/// Detects overlapping entities and generates collision events for gameplay systems. /// Detects overlapping entities and generates collision events for gameplay systems.
/// ///
/// Performs distance-based collision detection between Pac-Man and collectible items /// Performs distance-based collision detection between Pac-Man and collectible items
@@ -16,42 +35,49 @@ use crate::systems::movement::Position;
/// a `GameEvent::Collision` for the item system to handle scoring and removal. /// a `GameEvent::Collision` for the item system to handle scoring and removal.
/// Collision detection accounts for both entities being in motion and supports /// Collision detection accounts for both entities being in motion and supports
/// circular collision boundaries for accurate gameplay feel. /// circular collision boundaries for accurate gameplay feel.
///
/// Also detects collisions between Pac-Man and ghosts for gameplay mechanics like
/// power pellet effects, ghost eating, and player death.
pub fn collision_system( pub fn collision_system(
map: Res<Map>, map: Res<Map>,
pacman_query: Query<(Entity, &Position, &Collider), With<PacmanCollider>>, pacman_query: Query<(Entity, &Position, &Collider), With<PacmanCollider>>,
item_query: Query<(Entity, &Position, &Collider), With<ItemCollider>>, item_query: Query<(Entity, &Position, &Collider), With<ItemCollider>>,
ghost_query: Query<(Entity, &Position, &Collider), With<GhostCollider>>,
mut events: EventWriter<GameEvent>, mut events: EventWriter<GameEvent>,
mut errors: EventWriter<GameError>, mut errors: EventWriter<GameError>,
) { ) {
// Check PACMAN × ITEM collisions // Check PACMAN × ITEM collisions
for (pacman_entity, pacman_pos, pacman_collider) in pacman_query.iter() { for (pacman_entity, pacman_pos, pacman_collider) in pacman_query.iter() {
for (item_entity, item_pos, item_collider) in item_query.iter() { for (item_entity, item_pos, item_collider) in item_query.iter() {
match ( match check_collision(pacman_pos, pacman_collider, item_pos, item_collider, &map) {
pacman_pos.get_pixel_position(&map.graph), Ok(colliding) => {
item_pos.get_pixel_position(&map.graph), if colliding {
) {
(Ok(pacman_pixel), Ok(item_pixel)) => {
// Calculate the distance between the two entities's precise pixel positions
let distance = pacman_pixel.distance(item_pixel);
// Calculate the distance at which the two entities will collide
let collision_distance = (pacman_collider.size + item_collider.size) / 2.0;
// If the distance between the two entities is less than the collision distance, then the two entities are colliding
if distance < collision_distance {
events.write(GameEvent::Collision(pacman_entity, item_entity)); events.write(GameEvent::Collision(pacman_entity, item_entity));
} }
} }
// Either or both of the pixel positions failed to get, so we need to report the error Err(e) => {
(result_a, result_b) => { errors.write(GameError::InvalidState(format!(
for result in [result_a, result_b] { "Collision system failed to check collision between entities {:?} and {:?}: {}",
if let Err(e) = result { pacman_entity, item_entity, e
errors.write(GameError::InvalidState(format!( )));
"Collision system failed to get pixel positions for entities {:?} and {:?}: {}", }
pacman_entity, item_entity, e }
))); }
}
// Check PACMAN × GHOST collisions
for (ghost_entity, ghost_pos, ghost_collider) in ghost_query.iter() {
match check_collision(pacman_pos, pacman_collider, ghost_pos, ghost_collider, &map) {
Ok(colliding) => {
if colliding {
events.write(GameEvent::Collision(pacman_entity, ghost_entity));
} }
} }
Err(e) => {
errors.write(GameError::InvalidState(format!(
"Collision system failed to check collision between entities {:?} and {:?}: {}",
pacman_entity, ghost_entity, e
)));
}
} }
} }
} }

View File

@@ -114,6 +114,14 @@ pub struct Collider {
pub size: f32, pub size: f32,
} }
impl Collider {
/// Checks if this collider collides with another collider at the given distance.
pub fn collides_with(&self, other_size: f32, distance: f32) -> bool {
let collision_distance = (self.size + other_size) / 2.0;
distance < collision_distance
}
}
/// Marker components for collision filtering optimization /// Marker components for collision filtering optimization
#[derive(Component)] #[derive(Component)]
pub struct PacmanCollider; pub struct PacmanCollider;

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,79 +131,86 @@ 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 { // Find the closest node to the cursor
DebugState::Graph => {
// 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 {
map.graph map.graph
.nodes() .nodes()
.map(|node| node.position.distance(cursor_world_pos)) .map(|node| node.position.distance(cursor_world_pos))
.enumerate() .enumerate()
.min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Less)) .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Less))
.map(|(id, _)| id) .map(|(id, _)| id)
} else {
None
};
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() {
let start_node_model = map.graph.get_node(start_node).unwrap();
let end_node = map.graph.get_node(end_node.target).unwrap().position;
// Transform positions using common method
let start = transform_position_with_offset(start_node_model.position, scale);
let end = transform_position_with_offset(end_node, scale);
debug_canvas
.draw_line(Point::from((start.x, start.y)), Point::from((end.x, end.y)))
.unwrap();
}
for (id, node) in map.graph.nodes().enumerate() {
let pos = node.position;
// Set color based on whether the node is the closest to the cursor
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
} else { } else {
None Color::BLUE
}; })
});
debug_canvas.set_draw_color(Color::RED); // Transform position using common method
for (start_node, end_node) in map.graph.edges() { let pos = transform_position_with_offset(pos, scale);
let start_node_model = map.graph.get_node(start_node).unwrap(); let size = (2.0 * scale) as u32;
let end_node = map.graph.get_node(end_node.target).unwrap().position;
// Transform positions using common method debug_canvas
let start = transform_position_with_offset(start_node_model.position, scale); .fill_rect(Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size))
let end = transform_position_with_offset(end_node, scale); .unwrap();
}
debug_canvas // Render node ID if a node is highlighted
.draw_line(Point::from((start.x, start.y)), Point::from((end.x, end.y))) if let Some(closest_node_id) = closest_node {
.unwrap(); let node = map.graph.get_node(closest_node_id).unwrap();
} let pos = transform_position_with_offset(node.position, scale);
for (id, node) in map.graph.nodes().enumerate() { let surface = font
let pos = node.position; .render(&closest_node_id.to_string())
.blended(Color {
// Set color based on whether the node is the closest to the cursor a: f32_to_u8(0.4),
debug_canvas.set_draw_color(if Some(id) == closest_node { ..Color::WHITE
Color::YELLOW })
} else { .unwrap();
Color::BLUE 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);
debug_canvas.copy(&texture, None, dest).unwrap();
// Transform position using common method
let pos = transform_position_with_offset(pos, scale);
let size = (3.0 * scale) as u32;
debug_canvas
.fill_rect(Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size))
.unwrap();
}
// Render node ID if a node is highlighted
if let Some(closest_node_id) = closest_node {
let node = map.graph.get_node(closest_node_id).unwrap();
let pos = transform_position_with_offset(node.position, scale);
let surface = font.render(&closest_node_id.to_string()).blended(Color::WHITE).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);
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
@@ -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();
} }

150
tests/collision.rs Normal file
View File

@@ -0,0 +1,150 @@
use bevy_ecs::{event::Events, prelude::*, system::RunSystemOnce, world::World};
use pacman::{
error::GameError,
events::GameEvent,
map::builder::Map,
systems::{
collision::{check_collision, collision_system},
components::{Collider, EntityType, Ghost, GhostCollider, ItemCollider, PacmanCollider},
movement::Position,
},
};
fn create_test_world() -> World {
let mut world = World::new();
// Add required resources
world.insert_resource(Events::<GameEvent>::default());
world.insert_resource(Events::<GameError>::default());
// Add a minimal test map
world.insert_resource(create_test_map());
world
}
fn create_test_map() -> Map {
use pacman::constants::RAW_BOARD;
Map::new(RAW_BOARD).expect("Failed to create test map")
}
fn spawn_test_pacman(world: &mut World) -> Entity {
world
.spawn((Position::Stopped { node: 0 }, Collider { size: 10.0 }, PacmanCollider))
.id()
}
fn spawn_test_item(world: &mut World) -> Entity {
world
.spawn((
Position::Stopped { node: 0 },
Collider { size: 8.0 },
ItemCollider,
EntityType::Pellet,
))
.id()
}
fn spawn_test_ghost(world: &mut World) -> Entity {
world
.spawn((
Position::Stopped { node: 0 },
Collider { size: 12.0 },
GhostCollider,
Ghost::Blinky,
EntityType::Ghost,
))
.id()
}
fn spawn_test_ghost_at_node(world: &mut World, node: usize) -> Entity {
world
.spawn((
Position::Stopped { node },
Collider { size: 12.0 },
GhostCollider,
Ghost::Blinky,
EntityType::Ghost,
))
.id()
}
#[test]
fn test_collider_collision_detection() {
let collider1 = Collider { size: 10.0 };
let collider2 = Collider { size: 8.0 };
// Test collision detection
assert!(collider1.collides_with(collider2.size, 5.0)); // Should collide (distance < 9.0)
assert!(!collider1.collides_with(collider2.size, 15.0)); // Should not collide (distance > 9.0)
}
#[test]
fn test_check_collision_helper() {
let map = create_test_map();
let pos1 = Position::Stopped { node: 0 };
let pos2 = Position::Stopped { node: 0 }; // Same position
let collider1 = Collider { size: 10.0 };
let collider2 = Collider { size: 8.0 };
// Test collision at same position
let result = check_collision(&pos1, &collider1, &pos2, &collider2, &map);
assert!(result.is_ok());
assert!(result.unwrap()); // Should collide at same position
// Test collision at different positions
let pos3 = Position::Stopped { node: 1 }; // Different position
let result = check_collision(&pos1, &collider1, &pos3, &collider2, &map);
assert!(result.is_ok());
// May or may not collide depending on actual node positions
}
#[test]
fn test_collision_system_pacman_item() {
let mut world = create_test_world();
let _pacman = spawn_test_pacman(&mut world);
let _item = spawn_test_item(&mut world);
// Run collision system - should not panic
world
.run_system_once(collision_system)
.expect("System should run successfully");
}
#[test]
fn test_collision_system_pacman_ghost() {
let mut world = create_test_world();
let _pacman = spawn_test_pacman(&mut world);
let _ghost = spawn_test_ghost(&mut world);
// Run collision system - should not panic
world
.run_system_once(collision_system)
.expect("System should run successfully");
}
#[test]
fn test_collision_system_no_collision() {
let mut world = create_test_world();
let _pacman = spawn_test_pacman(&mut world);
let _ghost = spawn_test_ghost_at_node(&mut world, 1); // Different node
// Run collision system - should not panic
world
.run_system_once(collision_system)
.expect("System should run successfully");
}
#[test]
fn test_collision_system_multiple_entities() {
let mut world = create_test_world();
let _pacman = spawn_test_pacman(&mut world);
let _item = spawn_test_item(&mut world);
let _ghost = spawn_test_ghost(&mut world);
// Run collision system - should not panic
world
.run_system_once(collision_system)
.expect("System should run successfully");
}

View File

@@ -1,61 +1,6 @@
use pacman::events::{GameCommand, GameEvent}; use pacman::events::{GameCommand, GameEvent};
use pacman::map::direction::Direction; use pacman::map::direction::Direction;
#[test]
fn test_game_command_variants() {
// Test that all GameCommand variants can be created
let commands = [
GameCommand::Exit,
GameCommand::MovePlayer(Direction::Up),
GameCommand::MovePlayer(Direction::Down),
GameCommand::MovePlayer(Direction::Left),
GameCommand::MovePlayer(Direction::Right),
GameCommand::ToggleDebug,
GameCommand::MuteAudio,
GameCommand::ResetLevel,
GameCommand::TogglePause,
];
// Just verify they can be created and compared
assert_eq!(commands.len(), 9);
assert_eq!(commands[0], GameCommand::Exit);
assert_eq!(commands[1], GameCommand::MovePlayer(Direction::Up));
}
#[test]
fn test_game_command_equality() {
assert_eq!(GameCommand::Exit, GameCommand::Exit);
assert_eq!(GameCommand::ToggleDebug, GameCommand::ToggleDebug);
assert_eq!(
GameCommand::MovePlayer(Direction::Left),
GameCommand::MovePlayer(Direction::Left)
);
assert_ne!(GameCommand::Exit, GameCommand::ToggleDebug);
assert_ne!(
GameCommand::MovePlayer(Direction::Left),
GameCommand::MovePlayer(Direction::Right)
);
}
#[test]
fn test_game_event_variants() {
let command_event = GameEvent::Command(GameCommand::Exit);
let collision_event = GameEvent::Collision(bevy_ecs::entity::Entity::from_raw(1), bevy_ecs::entity::Entity::from_raw(2));
// Test that events can be created and compared
assert_eq!(command_event, GameEvent::Command(GameCommand::Exit));
assert_ne!(command_event, collision_event);
}
#[test]
fn test_game_command_to_game_event_conversion() {
let command = GameCommand::ToggleDebug;
let event: GameEvent = command.into();
assert_eq!(event, GameEvent::Command(GameCommand::ToggleDebug));
}
#[test] #[test]
fn test_game_command_to_game_event_conversion_all_variants() { fn test_game_command_to_game_event_conversion_all_variants() {
let commands = vec![ let commands = vec![
@@ -72,35 +17,3 @@ fn test_game_command_to_game_event_conversion_all_variants() {
assert_eq!(event, GameEvent::Command(command)); assert_eq!(event, GameEvent::Command(command));
} }
} }
#[test]
fn test_move_player_all_directions() {
let directions = [Direction::Up, Direction::Down, Direction::Left, Direction::Right];
for direction in directions {
let command = GameCommand::MovePlayer(direction);
let event: GameEvent = command.into();
if let GameEvent::Command(GameCommand::MovePlayer(dir)) = event {
assert_eq!(dir, direction);
} else {
panic!("Expected MovePlayer command with direction {:?}", direction);
}
}
}
#[test]
fn test_game_event_debug_format() {
let event = GameEvent::Command(GameCommand::Exit);
let debug_str = format!("{:?}", event);
assert!(debug_str.contains("Command"));
assert!(debug_str.contains("Exit"));
}
#[test]
fn test_game_command_debug_format() {
let command = GameCommand::MovePlayer(Direction::Left);
let debug_str = format!("{:?}", command);
assert!(debug_str.contains("MovePlayer"));
assert!(debug_str.contains("Left"));
}

View File

@@ -119,13 +119,6 @@ fn test_format_timing_display_basic() {
} }
} }
#[test]
fn test_format_timing_display_empty() {
let timing_data = vec![];
let formatted = format_timing_display(timing_data);
assert!(formatted.is_empty());
}
#[test] #[test]
fn test_format_timing_display_units() { fn test_format_timing_display_units() {
let timing_data = vec![ let timing_data = vec![

View File

@@ -16,7 +16,6 @@ fn test_calculate_score_for_item() {
assert!(EntityType::Pellet.score_value() < EntityType::PowerPellet.score_value()); assert!(EntityType::Pellet.score_value() < EntityType::PowerPellet.score_value());
assert!(EntityType::Pellet.score_value().is_some()); assert!(EntityType::Pellet.score_value().is_some());
assert!(EntityType::PowerPellet.score_value().is_some()); assert!(EntityType::PowerPellet.score_value().is_some());
assert!(EntityType::Pellet.score_value().unwrap() < EntityType::PowerPellet.score_value().unwrap());
assert!(EntityType::Player.score_value().is_none()); assert!(EntityType::Player.score_value().is_none());
assert!(EntityType::Ghost.score_value().is_none()); assert!(EntityType::Ghost.score_value().is_none());
} }
@@ -194,28 +193,6 @@ fn test_item_system_ignores_non_item_collisions() {
assert_eq!(ghost_count, 1); assert_eq!(ghost_count, 1);
} }
#[test]
fn test_item_system_wrong_collision_order() {
let mut world = create_test_world();
let pacman = spawn_test_pacman(&mut world);
let pellet = spawn_test_item(&mut world, EntityType::Pellet);
// Send collision event with entities in reverse order
send_collision_event(&mut world, pellet, pacman);
world.run_system_once(item_system).expect("System should run successfully");
// Should still work correctly
let score = world.resource::<ScoreResource>();
assert_eq!(score.0, 10);
let pellet_count = world
.query::<&EntityType>()
.iter(&world)
.filter(|&entity_type| matches!(entity_type, EntityType::Pellet))
.count();
assert_eq!(pellet_count, 0);
}
#[test] #[test]
fn test_item_system_no_collision_events() { fn test_item_system_no_collision_events() {
let mut world = create_test_world(); let mut world = create_test_world();

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