fix: flush world after switching to observer-based item collection

This commit is contained in:
Ryan Walters
2025-09-10 21:43:23 -05:00
parent d84f0c831e
commit d7a6ee7684
5 changed files with 21 additions and 22 deletions

2
Cargo.lock generated
View File

@@ -663,7 +663,7 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]] [[package]]
name = "pacman" name = "pacman"
version = "0.78.5" version = "0.79.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bevy_ecs", "bevy_ecs",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "pacman" name = "pacman"
version = "0.78.5" version = "0.79.0"
authors = ["Xevion"] authors = ["Xevion"]
edition = "2021" edition = "2021"
rust-version = "1.86.0" rust-version = "1.86.0"

View File

@@ -3,6 +3,7 @@
include!(concat!(env!("OUT_DIR"), "/atlas_data.rs")); include!(concat!(env!("OUT_DIR"), "/atlas_data.rs"));
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Not;
use tracing::{debug, info, trace, warn}; use tracing::{debug, info, trace, warn};
use crate::constants::{self, animation, MapTile, CANVAS_SIZE}; use crate::constants::{self, animation, MapTile, CANVAS_SIZE};
@@ -510,7 +511,7 @@ impl Game {
(|mut dirty: ResMut<RenderDirty>, score: Res<ScoreResource>, stage: Res<GameStage>| { (|mut dirty: ResMut<RenderDirty>, score: Res<ScoreResource>, stage: Res<GameStage>| {
dirty.0 = score.is_changed() || stage.is_changed(); dirty.0 = score.is_changed() || stage.is_changed();
}), }),
dirty_render_system.run_if(|dirty: Res<RenderDirty>| dirty.0 == false), dirty_render_system.run_if(|dirty: Res<RenderDirty>| dirty.0.not()),
combined_render_system, combined_render_system,
hud_render_system, hud_render_system,
touch_ui_render_system, touch_ui_render_system,

View File

@@ -162,7 +162,7 @@ pub fn ghost_collision_observer(
// Request transition via event so stage_system can process it // Request transition via event so stage_system can process it
stage_events.write(StageTransition::GhostEatenPause { stage_events.write(StageTransition::GhostEatenPause {
ghost_entity: ghost, ghost_entity: ghost,
ghost_type: ghost_type, ghost_type,
}); });
// Play eat sound // Play eat sound

View File

@@ -29,13 +29,13 @@ fn test_is_collectible_item() {
#[test] #[test]
fn test_item_system_pellet_collection() { fn test_item_system_pellet_collection() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
let pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet); let pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet);
// Send collision event // Send collision event
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: pellet }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: pellet });
schedule.run(&mut world); world.flush();
// Check that score was updated // Check that score was updated
let score = world.resource_mut::<ScoreResource>(); let score = world.resource_mut::<ScoreResource>();
@@ -52,12 +52,12 @@ fn test_item_system_pellet_collection() {
#[test] #[test]
fn test_item_system_power_pellet_collection() { fn test_item_system_power_pellet_collection() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
let power_pellet = common::spawn_test_item(&mut world, 1, EntityType::PowerPellet); let power_pellet = common::spawn_test_item(&mut world, 1, EntityType::PowerPellet);
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: power_pellet }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: power_pellet });
schedule.run(&mut world); world.flush();
// Check that score was updated with power pellet value // Check that score was updated with power pellet value
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();
@@ -74,7 +74,7 @@ fn test_item_system_power_pellet_collection() {
#[test] #[test]
fn test_item_system_multiple_collections() { fn test_item_system_multiple_collections() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
let pellet1 = common::spawn_test_item(&mut world, 1, EntityType::Pellet); let pellet1 = common::spawn_test_item(&mut world, 1, EntityType::Pellet);
let pellet2 = common::spawn_test_item(&mut world, 2, EntityType::Pellet); let pellet2 = common::spawn_test_item(&mut world, 2, EntityType::Pellet);
let power_pellet = common::spawn_test_item(&mut world, 3, EntityType::PowerPellet); let power_pellet = common::spawn_test_item(&mut world, 3, EntityType::PowerPellet);
@@ -84,14 +84,12 @@ fn test_item_system_multiple_collections() {
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: pellet2 }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: pellet2 });
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: power_pellet }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: power_pellet });
schedule.run(&mut world); world.flush();
// Check final score: 2 pellets (20) + 1 power pellet (50) = 70 // Check final score: 2 pellets (20) + 1 power pellet (50) = 70
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();
assert_that(&score.0).is_equal_to(70); assert_that(&score.0).is_equal_to(70);
schedule.run(&mut world);
// Check that all items were despawned // Check that all items were despawned
let pellet_count = world let pellet_count = world
.query::<&EntityType>() .query::<&EntityType>()
@@ -109,7 +107,7 @@ fn test_item_system_multiple_collections() {
#[test] #[test]
fn test_item_system_ignores_non_item_collisions() { fn test_item_system_ignores_non_item_collisions() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
// Create a ghost entity (not an item) // Create a ghost entity (not an item)
let ghost = world.spawn((Position::Stopped { node: 2 }, EntityType::Ghost)).id(); let ghost = world.spawn((Position::Stopped { node: 2 }, EntityType::Ghost)).id();
@@ -120,7 +118,7 @@ fn test_item_system_ignores_non_item_collisions() {
// Send collision event between pacman and ghost // Send collision event between pacman and ghost
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: ghost }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: ghost });
schedule.run(&mut world); world.flush();
// Score should remain unchanged // Score should remain unchanged
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();
@@ -137,14 +135,14 @@ fn test_item_system_ignores_non_item_collisions() {
#[test] #[test]
fn test_item_system_no_collision_events() { fn test_item_system_no_collision_events() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
let _pacman = common::spawn_test_pacman(&mut world, 0); let _pacman = common::spawn_test_pacman(&mut world, 0);
let _pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet); let _pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet);
let initial_score = world.resource::<ScoreResource>().0; let initial_score = world.resource::<ScoreResource>().0;
// Run system without any collision events // Run system without any collision events
schedule.run(&mut world); world.flush();
// Nothing should change // Nothing should change
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();
@@ -159,7 +157,7 @@ fn test_item_system_no_collision_events() {
#[test] #[test]
fn test_item_system_collision_with_missing_entity() { fn test_item_system_collision_with_missing_entity() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
// Create a fake entity ID that doesn't exist // Create a fake entity ID that doesn't exist
let fake_entity = Entity::from_raw(999); let fake_entity = Entity::from_raw(999);
@@ -167,7 +165,7 @@ fn test_item_system_collision_with_missing_entity() {
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: fake_entity }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: fake_entity });
// System should handle gracefully and not crash // System should handle gracefully and not crash
schedule.run(&mut world); world.flush();
// Score should remain unchanged // Score should remain unchanged
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();
assert_that(&score.0).is_equal_to(0); assert_that(&score.0).is_equal_to(0);
@@ -175,7 +173,7 @@ fn test_item_system_collision_with_missing_entity() {
#[test] #[test]
fn test_item_system_preserves_existing_score() { fn test_item_system_preserves_existing_score() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
// Set initial score // Set initial score
world.insert_resource(ScoreResource(100)); world.insert_resource(ScoreResource(100));
@@ -184,7 +182,7 @@ fn test_item_system_preserves_existing_score() {
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: pellet }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: pellet });
schedule.run(&mut world); world.flush();
// Score should be initial + pellet value // Score should be initial + pellet value
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();
@@ -193,7 +191,7 @@ fn test_item_system_preserves_existing_score() {
#[test] #[test]
fn test_power_pellet_does_not_affect_ghosts_in_eyes_state() { fn test_power_pellet_does_not_affect_ghosts_in_eyes_state() {
let (mut world, mut schedule) = common::create_test_world(); let (mut world, mut _schedule) = common::create_test_world();
let power_pellet = common::spawn_test_item(&mut world, 1, EntityType::PowerPellet); let power_pellet = common::spawn_test_item(&mut world, 1, EntityType::PowerPellet);
// Spawn a ghost in Eyes state (returning to ghost house) // Spawn a ghost in Eyes state (returning to ghost house)
@@ -204,7 +202,7 @@ fn test_power_pellet_does_not_affect_ghosts_in_eyes_state() {
common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: power_pellet }); common::trigger_collision(&mut world, CollisionTrigger::ItemCollision { item: power_pellet });
schedule.run(&mut world); world.flush();
// Check that the power pellet was collected and score updated // Check that the power pellet was collected and score updated
let score = world.resource::<ScoreResource>(); let score = world.resource::<ScoreResource>();