fix(game-state): reset score, lives, stage, and formation on restart; despawn explosions on cleanup
Reset Score, PlayerLives, CurrentStage, and FormationState resources when restarting from GameOver. Extend cleanup_game_entities to also despawn Explosion entities.
This commit is contained in:
parent
73c76e75be
commit
933d23cc35
1 changed files with 176 additions and 3 deletions
|
|
@ -1,9 +1,13 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
Bullet, Enemy, EnemyBullet, GameOverUI, HighScoreText, RestartMessage, StartButton, StartMenuUI,
|
Bullet, Enemy, EnemyBullet, Explosion, GameOverUI, HighScoreText, RestartMessage, StartButton,
|
||||||
|
StartMenuUI,
|
||||||
|
};
|
||||||
|
use crate::constants::STARTING_LIVES;
|
||||||
|
use crate::resources::{
|
||||||
|
CurrentStage, FormationState, HighScore, PlayerLives, RestartPressed, Score,
|
||||||
};
|
};
|
||||||
use crate::resources::{HighScore, RestartPressed, Score};
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
|
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
|
||||||
pub enum AppState {
|
pub enum AppState {
|
||||||
|
|
@ -85,7 +89,15 @@ pub fn cleanup_game_over_ui(
|
||||||
|
|
||||||
pub fn cleanup_game_entities(
|
pub fn cleanup_game_entities(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Query<Entity, Or<(With<Bullet>, With<EnemyBullet>, With<Enemy>)>>,
|
query: Query<
|
||||||
|
Entity,
|
||||||
|
Or<(
|
||||||
|
With<Bullet>,
|
||||||
|
With<EnemyBullet>,
|
||||||
|
With<Enemy>,
|
||||||
|
With<Explosion>,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
for entity in &query {
|
for entity in &query {
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
|
|
@ -198,9 +210,170 @@ pub fn handle_restart_input(
|
||||||
pub fn restart_game_system(
|
pub fn restart_game_system(
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
mut restart: ResMut<RestartPressed>,
|
mut restart: ResMut<RestartPressed>,
|
||||||
|
mut score: ResMut<Score>,
|
||||||
|
mut lives: ResMut<PlayerLives>,
|
||||||
|
mut stage: ResMut<CurrentStage>,
|
||||||
|
mut formation: ResMut<FormationState>,
|
||||||
) {
|
) {
|
||||||
if restart.pressed {
|
if restart.pressed {
|
||||||
restart.pressed = false;
|
restart.pressed = false;
|
||||||
|
score.value = 0;
|
||||||
|
lives.count = STARTING_LIVES;
|
||||||
|
stage.number = 1;
|
||||||
|
stage.waiting_for_clear = false;
|
||||||
|
formation.next_slot_index = 0;
|
||||||
|
formation.total_spawned_this_stage = 0;
|
||||||
|
formation.formation_complete = false;
|
||||||
next_state.set(AppState::Playing);
|
next_state.set(AppState::Playing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::components::Explosion;
|
||||||
|
use crate::constants::STARTING_LIVES;
|
||||||
|
use crate::resources::{CurrentStage, FormationState, PlayerLives};
|
||||||
|
use bevy::ecs::world::World;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn restart_game_resets_score_to_zero() {
|
||||||
|
let mut world = World::default();
|
||||||
|
world.insert_resource(Score { value: 5000 });
|
||||||
|
world.insert_resource(PlayerLives { count: 1 });
|
||||||
|
world.insert_resource(CurrentStage {
|
||||||
|
number: 5,
|
||||||
|
waiting_for_clear: true,
|
||||||
|
});
|
||||||
|
world.insert_resource(FormationState {
|
||||||
|
next_slot_index: 4,
|
||||||
|
total_spawned_this_stage: 10,
|
||||||
|
formation_complete: true,
|
||||||
|
});
|
||||||
|
world.insert_resource(NextState::<AppState>::Pending(AppState::Playing));
|
||||||
|
world.insert_resource(RestartPressed { pressed: true });
|
||||||
|
|
||||||
|
world.register_system(restart_game_system);
|
||||||
|
world
|
||||||
|
.run_system_cached(restart_game_system)
|
||||||
|
.expect("system should run");
|
||||||
|
|
||||||
|
let score = world.resource::<Score>();
|
||||||
|
assert_eq!(score.value, 0, "Score should be reset to 0 on restart");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn restart_game_resets_player_lives_to_starting_lives() {
|
||||||
|
let mut world = World::default();
|
||||||
|
world.insert_resource(Score { value: 5000 });
|
||||||
|
world.insert_resource(PlayerLives { count: 1 });
|
||||||
|
world.insert_resource(CurrentStage {
|
||||||
|
number: 1,
|
||||||
|
waiting_for_clear: false,
|
||||||
|
});
|
||||||
|
world.insert_resource(FormationState::default());
|
||||||
|
world.insert_resource(NextState::<AppState>::Pending(AppState::Playing));
|
||||||
|
world.insert_resource(RestartPressed { pressed: true });
|
||||||
|
|
||||||
|
world.register_system(restart_game_system);
|
||||||
|
world
|
||||||
|
.run_system_cached(restart_game_system)
|
||||||
|
.expect("system should run");
|
||||||
|
|
||||||
|
let lives = world.resource::<PlayerLives>();
|
||||||
|
assert_eq!(
|
||||||
|
lives.count, STARTING_LIVES,
|
||||||
|
"PlayerLives should be reset to STARTING_LIVES on restart"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn restart_game_resets_current_stage_to_defaults() {
|
||||||
|
let mut world = World::default();
|
||||||
|
world.insert_resource(Score { value: 0 });
|
||||||
|
world.insert_resource(PlayerLives {
|
||||||
|
count: STARTING_LIVES,
|
||||||
|
});
|
||||||
|
world.insert_resource(CurrentStage {
|
||||||
|
number: 5,
|
||||||
|
waiting_for_clear: true,
|
||||||
|
});
|
||||||
|
world.insert_resource(FormationState::default());
|
||||||
|
world.insert_resource(NextState::<AppState>::Pending(AppState::Playing));
|
||||||
|
world.insert_resource(RestartPressed { pressed: true });
|
||||||
|
|
||||||
|
world.register_system(restart_game_system);
|
||||||
|
world
|
||||||
|
.run_system_cached(restart_game_system)
|
||||||
|
.expect("system should run");
|
||||||
|
|
||||||
|
let stage = world.resource::<CurrentStage>();
|
||||||
|
assert_eq!(
|
||||||
|
stage.number, 1,
|
||||||
|
"CurrentStage.number should be reset to 1 on restart"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
stage.waiting_for_clear, false,
|
||||||
|
"CurrentStage.waiting_for_clear should be reset to false on restart"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn restart_game_resets_formation_state_to_defaults() {
|
||||||
|
let mut world = World::default();
|
||||||
|
world.insert_resource(Score { value: 0 });
|
||||||
|
world.insert_resource(PlayerLives {
|
||||||
|
count: STARTING_LIVES,
|
||||||
|
});
|
||||||
|
world.insert_resource(CurrentStage {
|
||||||
|
number: 1,
|
||||||
|
waiting_for_clear: false,
|
||||||
|
});
|
||||||
|
world.insert_resource(FormationState {
|
||||||
|
next_slot_index: 4,
|
||||||
|
total_spawned_this_stage: 10,
|
||||||
|
formation_complete: true,
|
||||||
|
});
|
||||||
|
world.insert_resource(NextState::<AppState>::Pending(AppState::Playing));
|
||||||
|
world.insert_resource(RestartPressed { pressed: true });
|
||||||
|
|
||||||
|
world.register_system(restart_game_system);
|
||||||
|
world
|
||||||
|
.run_system_cached(restart_game_system)
|
||||||
|
.expect("system should run");
|
||||||
|
|
||||||
|
let formation = world.resource::<FormationState>();
|
||||||
|
assert_eq!(
|
||||||
|
formation.next_slot_index, 0,
|
||||||
|
"FormationState.next_slot_index should be reset to 0"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
formation.total_spawned_this_stage, 0,
|
||||||
|
"FormationState.total_spawned_this_stage should be reset to 0"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
formation.formation_complete, false,
|
||||||
|
"FormationState.formation_complete should be reset to false"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cleanup_game_entities_despawns_explosions() {
|
||||||
|
let mut world = World::default();
|
||||||
|
world.spawn(Explosion {
|
||||||
|
timer: Timer::from_seconds(0.4, TimerMode::Once),
|
||||||
|
});
|
||||||
|
|
||||||
|
world.register_system(cleanup_game_entities);
|
||||||
|
world
|
||||||
|
.run_system_cached(cleanup_game_entities)
|
||||||
|
.expect("system should run");
|
||||||
|
|
||||||
|
let mut query = world.query::<&Explosion>();
|
||||||
|
let explosion_count = query.iter(&world).count();
|
||||||
|
assert_eq!(
|
||||||
|
explosion_count, 0,
|
||||||
|
"Explosion entities should be despawned during cleanup"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue