From cd194e2dbf3c4671bd204295d4ef975f43aa829e Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Mon, 11 Aug 2025 23:07:18 -0500 Subject: [PATCH] Move collision system to physics module --- src/lib.rs | 67 ++---------------------------------------------- src/physics.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1f67644..f487306 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ use crate::config::{ PLAYER_SHIP_COLOR, SHIP_ROTATION, SHIP_THRUST, SHIP_THRUSTER_COLOR_ACTIVE, SHIP_THRUSTER_COLOR_INACTIVE, WINDOW_SIZE, }; -use crate::objects::{Asteroid, Bullet, Ship}; +use crate::objects::{Bullet, Ship}; use crate::physics::AngularVelocity; use bevy::prelude::*; @@ -61,7 +61,7 @@ impl Plugin for AsteroidPlugin { objects::split_asteroids, objects::bullet_impact_listener, objects::ship_impact_listener, - collision_listener, + physics::collision_listener, // TODO: Remove debug printing debug_collision_event_printer, tick_lifetimes, @@ -90,69 +90,6 @@ fn debug_collision_event_printer(mut collision_events: EventReader, - mut ship_writer: EventWriter, - mut asteroid_writer: EventWriter, - mut bullet_writer: EventWriter, - player: Single>, - bullets: Query<&Bullet>, - rocks: Query<&Asteroid>, -) { - for event in collisions.read() { - if let CollisionEvent::Started(one, two, _flags) = event { - // Valid collisions are: - // - // - Ship & Asteroid - // - Bullet & Asteroid - // - // Asteroids don't collide with each other, bullets don't collide - // with each other, and bullets don't collide with the player ship. - - // Option 1: Ship & Asteroid - if *one == *player { - if rocks.contains(*two) { - // player-asteroid collision - dbg!("Writing ShipDestroy event"); - ship_writer.write(events::ShipDestroy); - } // else, we don't care - } else if *two == *player { - if rocks.contains(*one) { - dbg!("Writing ShipDestroy event"); - ship_writer.write(events::ShipDestroy); - } - } - - // Option 2: Bullet & Asteroid - if bullets.contains(*one) { - if rocks.contains(*two) { - dbg!("Writing AsteroidDestroy & BulletDestroy events"); - asteroid_writer.write(events::AsteroidDestroy(*two)); - bullet_writer.write(events::BulletDestroy(*one)); - } - } else if rocks.contains(*one) { - if bullets.contains(*two) { - dbg!("Writing AsteroidDestroy & BulletDestroy events"); - asteroid_writer.write(events::AsteroidDestroy(*one)); - bullet_writer.write(events::BulletDestroy(*two)); - } - } - } - } -} - #[derive(Clone, Debug, Eq, Hash, PartialEq, States)] pub enum GameState { TitleScreen, // Program is started. Present title screen and await user start diff --git a/src/physics.rs b/src/physics.rs index dabe837..6bc3fac 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,9 +1,13 @@ //! Custom physics items //! TODO: Refactor in terms of Rapier2D, *or* implement colliders and remove it. -use crate::WorldSize; +use crate::{ + WorldSize, events, + objects::{Asteroid, Bullet, Ship}, +}; use bevy::prelude::*; +use bevy_rapier2d::pipeline::CollisionEvent; #[derive(Clone, Component)] pub(crate) struct Velocity(pub(crate) bevy::math::Vec2); @@ -57,3 +61,66 @@ pub(crate) fn wrap_entities( } } } + +/// The collision event routing system. +/// +/// When a `CollisionEvent` occurrs, this system checks which things collided +/// and emits secondary events accordignly. +/// +/// | Objects | Response | +/// |-|-| +/// | Ship & Asteroid | emits event [`ShipDestroy`](`crate::event::ShipDestroy`) | +/// | Asteroid & Bullet | emits event [`AsteroidDestroy`](`crate::event::AsteroidDestroy`) | +/// | Asteroid & Asteroid | Nothing. Asteroids won't collide with each other | +/// | Bullet & Bullet | Nothing. Bullets won't collide with each other (and probably can't under normal gameplay conditions) | +/// | Bullet & Ship | Nothing. The player shouldn't be able to shoot themselves (and the Flying Saucer hasn't been impl.'d, so it's bullets don't count) | +pub fn collision_listener( + mut collisions: EventReader, + mut ship_writer: EventWriter, + mut asteroid_writer: EventWriter, + mut bullet_writer: EventWriter, + player: Single>, + bullets: Query<&Bullet>, + rocks: Query<&Asteroid>, +) { + for event in collisions.read() { + if let CollisionEvent::Started(one, two, _flags) = event { + // Valid collisions are: + // + // - Ship & Asteroid + // - Bullet & Asteroid + // + // Asteroids don't collide with each other, bullets don't collide + // with each other, and bullets don't collide with the player ship. + + // Option 1: Ship & Asteroid + if *one == *player { + if rocks.contains(*two) { + // player-asteroid collision + dbg!("Writing ShipDestroy event"); + ship_writer.write(events::ShipDestroy); + } // else, we don't care + } else if *two == *player { + if rocks.contains(*one) { + dbg!("Writing ShipDestroy event"); + ship_writer.write(events::ShipDestroy); + } + } + + // Option 2: Bullet & Asteroid + if bullets.contains(*one) { + if rocks.contains(*two) { + dbg!("Writing AsteroidDestroy & BulletDestroy events"); + asteroid_writer.write(events::AsteroidDestroy(*two)); + bullet_writer.write(events::BulletDestroy(*one)); + } + } else if rocks.contains(*one) { + if bullets.contains(*two) { + dbg!("Writing AsteroidDestroy & BulletDestroy events"); + asteroid_writer.write(events::AsteroidDestroy(*one)); + bullet_writer.write(events::BulletDestroy(*two)); + } + } + } + } +}