From 1369a3092f16cda57b7e9fa545d27ae9879b9d66 Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Mon, 11 Aug 2025 23:01:14 -0500 Subject: [PATCH] Move the ship & bullet systems into the object mod --- src/lib.rs | 10 +++--- src/objects.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++---- src/ship.rs | 76 ---------------------------------------------- 3 files changed, 82 insertions(+), 86 deletions(-) delete mode 100644 src/ship.rs diff --git a/src/lib.rs b/src/lib.rs index 7616d0a..1f67644 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ mod events; mod objects; mod physics; mod preparation_widget; -mod ship; mod title_screen; use crate::asteroids::AsteroidSpawner; @@ -46,7 +45,10 @@ impl Plugin for AsteroidPlugin { .insert_resource(AsteroidSpawner::new()) .init_resource::() .add_systems(Startup, spawn_camera) - .add_systems(OnEnter(GameState::Playing), (ship::spawn_player, spawn_ui)) + .add_systems( + OnEnter(GameState::Playing), + (objects::spawn_player, spawn_ui), + ) .add_systems( FixedUpdate, ( @@ -57,8 +59,8 @@ impl Plugin for AsteroidPlugin { asteroids::tick_asteroid_manager, objects::spawn_asteroid.after(asteroids::tick_asteroid_manager), objects::split_asteroids, - ship::bullet_impact_listener, - ship::ship_impact_listener, + objects::bullet_impact_listener, + objects::ship_impact_listener, collision_listener, // TODO: Remove debug printing debug_collision_event_printer, diff --git a/src/objects.rs b/src/objects.rs index 385df61..5f4b1df 100644 --- a/src/objects.rs +++ b/src/objects.rs @@ -5,23 +5,26 @@ use bevy::{ ecs::{ component::Component, + entity::Entity, event::{EventReader, EventWriter}, - system::{Commands, Query, Res}, + query::With, + system::{Commands, Query, Res, ResMut, Single}, }, - math::{Vec2, Vec3Swizzles}, + math::{Vec2, Vec3, Vec3Swizzles}, prelude::{Deref, DerefMut}, render::mesh::Mesh2d, sprite::MeshMaterial2d, + state::state::NextState, time::{Timer, TimerMode}, transform::components::Transform, }; -use bevy_rapier2d::prelude::{Collider, Sensor}; +use bevy_rapier2d::prelude::{ActiveCollisionTypes, ActiveEvents, Collider, Sensor}; use crate::{ - GameAssets, Lifetime, + AngularVelocity, GameAssets, GameState, Lifetime, Lives, config::ASTEROID_LIFETIME, - events::{AsteroidDestroy, SpawnAsteroid}, - physics::Velocity, + events::{AsteroidDestroy, BulletDestroy, ShipDestroy, SpawnAsteroid}, + physics::{Velocity, Wrapping}, }; #[derive(Component, Deref, DerefMut)] @@ -121,3 +124,70 @@ pub fn split_asteroids( } } } + +pub fn spawn_player(mut commands: Commands, game_assets: Res) { + commands + .spawn(( + Collider::ball(0.7), + Sensor, + ActiveEvents::COLLISION_EVENTS, + ActiveCollisionTypes::STATIC_STATIC, + Ship, + Wrapping, + Velocity(Vec2::ZERO), + AngularVelocity(0.0), + Mesh2d(game_assets.ship().0), + MeshMaterial2d(game_assets.ship().1), + Transform::default().with_scale(Vec3::new(20.0, 20.0, 20.0)), + )) + .with_child(( + Mesh2d(game_assets.thruster_mesh()), + MeshMaterial2d(game_assets.thruster_mat_inactive()), + Transform::default() + .with_scale(Vec3::splat(0.5)) + .with_translation(Vec3::new(-0.5, 0.0, -0.1)), + )); +} + +/// Watch for [`BulletDestroy`] events and despawn +/// the associated bullet. +pub fn bullet_impact_listener(mut commands: Commands, mut events: EventReader) { + for event in events.read() { + commands.entity(event.0).despawn(); + } +} + +/// Watch for [`ShipDestroy`] events and update game state accordingly. +/// +/// - Subtract a life +/// - Check life count. If 0, go to game-over state +/// - Clear all asteroids +/// - Respawn player +pub fn ship_impact_listener( + mut events: EventReader, + mut commands: Commands, + mut lives: ResMut, + rocks: Query>, + mut player: Single<(&mut Transform, &mut Velocity), With>, + mut next_state: ResMut>, +) { + for _ in events.read() { + // STEP 1: Decrement lives (and maybe go to game over) + if lives.0 == 0 { + // If already at 0, game is over. + next_state.set(GameState::GameOver); + } else { + // Decrease life count. + lives.0 -= 1; + } + + // STEP 2: Clear asteroids + for rock in rocks { + commands.entity(rock).despawn(); + } + + // STEP 3: Respawn player (teleport them to the origin) + player.0.translation = Vec3::ZERO; + player.1.0 = Vec2::ZERO; + } +} diff --git a/src/ship.rs b/src/ship.rs deleted file mode 100644 index 8c6f0c7..0000000 --- a/src/ship.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::{ - AngularVelocity, GameAssets, GameState, Lives, - events::{BulletDestroy, ShipDestroy}, - objects::{Asteroid, Ship}, - physics::{Velocity, Wrapping}, -}; - -use bevy::prelude::*; -use bevy_rapier2d::prelude::*; - -pub fn spawn_player(mut commands: Commands, game_assets: Res) { - commands - .spawn(( - Collider::ball(0.7), - Sensor, - ActiveEvents::COLLISION_EVENTS, - ActiveCollisionTypes::STATIC_STATIC, - Ship, - Wrapping, - Velocity(Vec2::ZERO), - AngularVelocity(0.0), - Mesh2d(game_assets.ship().0), - MeshMaterial2d(game_assets.ship().1), - Transform::default().with_scale(Vec3::new(20.0, 20.0, 20.0)), - )) - .with_child(( - Mesh2d(game_assets.thruster_mesh()), - MeshMaterial2d(game_assets.thruster_mat_inactive()), - Transform::default() - .with_scale(Vec3::splat(0.5)) - .with_translation(Vec3::new(-0.5, 0.0, -0.1)), - )); -} - -/// Watch for [`BulletDestroy`] events and despawn -/// the associated bullet. -pub fn bullet_impact_listener(mut commands: Commands, mut events: EventReader) { - for event in events.read() { - commands.entity(event.0).despawn(); - } -} - -/// Watch for [`ShipDestroy`] events and update game state accordingly. -/// -/// - Subtract a life -/// - Check life count. If 0, go to game-over state -/// - Clear all asteroids -/// - Respawn player -pub fn ship_impact_listener( - mut events: EventReader, - mut commands: Commands, - mut lives: ResMut, - rocks: Query>, - mut player: Single<(&mut Transform, &mut Velocity), With>, - mut next_state: ResMut>, -) { - for _ in events.read() { - // STEP 1: Decrement lives (and maybe go to game over) - if lives.0 == 0 { - // If already at 0, game is over. - next_state.set(GameState::GameOver); - } else { - // Decrease life count. - lives.0 -= 1; - } - - // STEP 2: Clear asteroids - for rock in rocks { - commands.entity(rock).despawn(); - } - - // STEP 3: Respawn player (teleport them to the origin) - player.0.translation = Vec3::ZERO; - player.1.0 = Vec2::ZERO; - } -}