3 Commits

Author SHA1 Message Date
45b1fe751f Create the asteroid splitter to break down rocks.
Some checks failed
Basic checks / Basic build-and-test supertask (push) Has been cancelled
2025-08-10 20:45:08 -05:00
3d28d489b0 Fix: Pass size through to spawned asteroid
I actually have most of the asteroid's destruction handling system done
and found this bug.

Asteroid *assets* are selected based on the size set in the spawn event,
but the `Asteroid` Component itself was left hard-coded to the smallest
size.
2025-08-10 18:46:49 -05:00
cdd665cc93 Add bullet on-impact despawning system 2025-08-10 18:43:56 -05:00
3 changed files with 67 additions and 2 deletions

View File

@@ -7,17 +7,31 @@ use std::time::Duration;
use bevy::prelude::*; use bevy::prelude::*;
use crate::{GameAssets, Lifetime, WorldSize, config::ASTEROID_LIFETIME, physics::Velocity}; use crate::{
GameAssets, Lifetime, WorldSize, config::ASTEROID_LIFETIME, event::AsteroidDestroy,
physics::Velocity,
};
#[derive(Component, Deref, DerefMut)] #[derive(Component, Deref, DerefMut)]
pub struct Asteroid(AsteroidSize); pub struct Asteroid(AsteroidSize);
#[derive(Clone, Copy, Debug)]
pub enum AsteroidSize { pub enum AsteroidSize {
Small, Small,
Medium, Medium,
Large, Large,
} }
impl AsteroidSize {
fn next(&self) -> Option<Self> {
match self {
AsteroidSize::Small => None,
AsteroidSize::Medium => Some(AsteroidSize::Small),
AsteroidSize::Large => Some(AsteroidSize::Medium),
}
}
}
#[derive(Resource)] #[derive(Resource)]
pub struct AsteroidSpawner { pub struct AsteroidSpawner {
rng: std::sync::Mutex<rand::rngs::StdRng>, rng: std::sync::Mutex<rand::rngs::StdRng>,
@@ -117,7 +131,7 @@ pub fn spawn_asteroid(
}; };
commands.spawn(( commands.spawn((
Asteroid(AsteroidSize::Small), Asteroid(spawn.size),
Collider::ball(collider_radius), Collider::ball(collider_radius),
Sensor, Sensor,
Transform::from_translation(spawn.pos.extend(0.0)), Transform::from_translation(spawn.pos.extend(0.0)),
@@ -128,3 +142,43 @@ pub fn spawn_asteroid(
)); ));
} }
} }
/// Event listener for asteroid destruction events. Shrinks and multiplies
/// asteroids until they vanish.
///
/// - Large -> 2x Medium
/// - Medium -> 2x Small
/// - Small -> (despawned)
///
/// The velocity of the child asteroids is scattered somewhat, as if they were
/// explosively pushed apart.
pub fn split_asteroids(
mut destroy_events: EventReader<AsteroidDestroy>,
mut respawn_events: EventWriter<SpawnAsteroid>,
mut commands: Commands,
query: Query<(&Transform, &Asteroid, &Velocity)>,
) {
for event in destroy_events.read() {
if let Ok((transform, rock, velocity)) = query.get(event.0) {
let next_size = rock.0.next();
if let Some(size) = next_size {
let pos = transform.translation.xy();
let left_offset = Vec2::from_angle(0.4);
let right_offset = Vec2::from_angle(-0.4);
respawn_events.write(SpawnAsteroid {
pos,
vel: left_offset.rotate(velocity.0),
size,
});
respawn_events.write(SpawnAsteroid {
pos,
vel: right_offset.rotate(velocity.0),
size,
});
}
// Always despawn the asteroid. New ones (may) be spawned in it's
// place, but this one is gone.
commands.entity(event.0).despawn();
}
}
}

View File

@@ -55,6 +55,8 @@ impl Plugin for AsteroidPlugin {
physics::wrap_entities, physics::wrap_entities,
asteroids::tick_asteroid_manager, asteroids::tick_asteroid_manager,
asteroids::spawn_asteroid.after(asteroids::tick_asteroid_manager), asteroids::spawn_asteroid.after(asteroids::tick_asteroid_manager),
asteroids::split_asteroids,
ship::bullet_impact_listener,
collision_listener, collision_listener,
// TODO: Remove debug printing // TODO: Remove debug printing
debug_collision_event_printer, debug_collision_event_printer,

View File

@@ -1,5 +1,6 @@
use crate::{ use crate::{
AngularVelocity, GameAssets, AngularVelocity, GameAssets,
event::BulletDestroy,
physics::{Velocity, Wrapping}, physics::{Velocity, Wrapping},
}; };
@@ -35,3 +36,11 @@ pub fn spawn_player(mut commands: Commands, game_assets: Res<GameAssets>) {
.with_translation(Vec3::new(-0.5, 0.0, -0.1)), .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<BulletDestroy>) {
for event in events.read() {
commands.entity(event.0).despawn();
}
}