3 Commits

Author SHA1 Message Date
364fbd7530 Use the lifetime limiters on Bullets & Asteroids
All checks were successful
Basic checks / Basic build-and-test supertask (push) Successful in 7m3s
Closes #14

Despawn bullets to limit range.

Despawn asteroids to limit random garbage floating around the scene.
2025-08-10 17:14:26 -05:00
2f463303a0 Create Lifetime component and system
Closes #13

The lifetime component, and system to operate it, are ready! Now I can
delete things that have lived for too long.
2025-08-10 17:07:20 -05:00
8d689d7842 Wire in the bullet & asteroid destruction events 2025-08-10 16:49:22 -05:00
3 changed files with 41 additions and 7 deletions

View File

@@ -7,7 +7,7 @@ use std::time::Duration;
use bevy::prelude::*; use bevy::prelude::*;
use crate::{GameAssets, WorldSize, physics::Velocity}; use crate::{GameAssets, Lifetime, WorldSize, config::ASTEROID_LIFETIME, physics::Velocity};
#[derive(Component, Deref, DerefMut)] #[derive(Component, Deref, DerefMut)]
pub struct Asteroid(AsteroidSize); pub struct Asteroid(AsteroidSize);
@@ -124,6 +124,7 @@ pub fn spawn_asteroid(
Velocity(spawn.vel), Velocity(spawn.vel),
Mesh2d(mesh), Mesh2d(mesh),
MeshMaterial2d(material), MeshMaterial2d(material),
Lifetime(Timer::from_seconds(ASTEROID_LIFETIME, TimerMode::Once)),
)); ));
} }
} }

View File

@@ -17,5 +17,8 @@ pub(crate) const SHIP_THRUST: f32 = 1.0;
pub(crate) const SHIP_ROTATION: f32 = 4.0; // +/- rotation speed in... radians per frame pub(crate) const SHIP_ROTATION: f32 = 4.0; // +/- rotation speed in... radians per frame
pub(crate) const BULLET_SPEED: f32 = 150.0; pub(crate) const BULLET_SPEED: f32 = 150.0;
pub(crate) const BULLET_LIFETIME: f32 = 2.0;
pub(crate) const ASTEROID_LIFETIME: f32 = 40.0;
pub const RNG_SEED: [u8; 32] = *b"12345678909876543210123456789098"; pub const RNG_SEED: [u8; 32] = *b"12345678909876543210123456789098";

View File

@@ -8,12 +8,12 @@ mod title_screen;
use crate::asteroids::{Asteroid, AsteroidSpawner}; use crate::asteroids::{Asteroid, AsteroidSpawner};
use crate::config::{ use crate::config::{
ASTEROID_SMALL_COLOR, BACKGROUND_COLOR, BULLET_COLOR, BULLET_SPEED, PLAYER_SHIP_COLOR, ASTEROID_SMALL_COLOR, BACKGROUND_COLOR, BULLET_COLOR, BULLET_LIFETIME, BULLET_SPEED,
SHIP_ROTATION, SHIP_THRUST, SHIP_THRUSTER_COLOR_ACTIVE, SHIP_THRUSTER_COLOR_INACTIVE, PLAYER_SHIP_COLOR, SHIP_ROTATION, SHIP_THRUST, SHIP_THRUSTER_COLOR_ACTIVE,
WINDOW_SIZE, SHIP_THRUSTER_COLOR_INACTIVE, WINDOW_SIZE,
}; };
use crate::physics::AngularVelocity; use crate::physics::AngularVelocity;
use crate::ship::Ship; use crate::ship::{Bullet, Ship};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::InspectorOptions; use bevy_inspector_egui::InspectorOptions;
@@ -58,6 +58,7 @@ impl Plugin for AsteroidPlugin {
collision_listener, collision_listener,
// TODO: Remove debug printing // TODO: Remove debug printing
debug_collision_event_printer, debug_collision_event_printer,
tick_lifetimes,
) )
.run_if(in_state(GameState::Playing)), .run_if(in_state(GameState::Playing)),
) )
@@ -71,7 +72,8 @@ impl Plugin for AsteroidPlugin {
) )
.add_event::<asteroids::SpawnAsteroid>() .add_event::<asteroids::SpawnAsteroid>()
.add_event::<event::AsteroidDestroy>() .add_event::<event::AsteroidDestroy>()
.add_event::<event::ShipDestroy>(); .add_event::<event::ShipDestroy>()
.add_event::<event::BulletDestroy>();
app.insert_state(GameState::Playing); app.insert_state(GameState::Playing);
} }
} }
@@ -98,7 +100,9 @@ fn collision_listener(
mut collisions: EventReader<CollisionEvent>, mut collisions: EventReader<CollisionEvent>,
mut ship_writer: EventWriter<event::ShipDestroy>, mut ship_writer: EventWriter<event::ShipDestroy>,
mut asteroid_writer: EventWriter<event::AsteroidDestroy>, mut asteroid_writer: EventWriter<event::AsteroidDestroy>,
mut bullet_writer: EventWriter<event::BulletDestroy>,
player: Single<Entity, With<Ship>>, player: Single<Entity, With<Ship>>,
bullets: Query<&Bullet>,
rocks: Query<&Asteroid>, rocks: Query<&Asteroid>,
) { ) {
for event in collisions.read() { for event in collisions.read() {
@@ -125,7 +129,20 @@ fn collision_listener(
} }
} }
// TODO: Bullet-asteroid collisions // Option 2: Bullet & Asteroid
if bullets.contains(*one) {
if rocks.contains(*two) {
dbg!("Writing AsteroidDestroy & BulletDestroy events");
asteroid_writer.write(event::AsteroidDestroy(*two));
bullet_writer.write(event::BulletDestroy(*one));
}
} else if rocks.contains(*one) {
if bullets.contains(*two) {
dbg!("Writing AsteroidDestroy & BulletDestroy events");
asteroid_writer.write(event::AsteroidDestroy(*one));
bullet_writer.write(event::BulletDestroy(*two));
}
}
} }
} }
} }
@@ -147,6 +164,9 @@ impl From<Score> for String {
} }
} }
#[derive(Component)]
struct Lifetime(Timer);
#[derive(InspectorOptions, Reflect, Resource, Debug, Deref, Clone, Copy)] #[derive(InspectorOptions, Reflect, Resource, Debug, Deref, Clone, Copy)]
#[reflect(Resource, InspectorOptions)] #[reflect(Resource, InspectorOptions)]
struct Lives(i32); struct Lives(i32);
@@ -320,6 +340,7 @@ fn input_ship_shoot(
Mesh2d(game_assets.bullet().0), Mesh2d(game_assets.bullet().0),
MeshMaterial2d(game_assets.bullet().1), MeshMaterial2d(game_assets.bullet().1),
ship_pos.clone(), // clone ship transform ship_pos.clone(), // clone ship transform
Lifetime(Timer::from_seconds(BULLET_LIFETIME, TimerMode::Once)),
)); ));
} }
} }
@@ -330,3 +351,12 @@ fn spawn_ui(mut commands: Commands, score: Res<Score>, lives: Res<Lives>) {
TextFont::from_font_size(25.0), TextFont::from_font_size(25.0),
)); ));
} }
fn tick_lifetimes(mut commands: Commands, time: Res<Time>, query: Query<(Entity, &mut Lifetime)>) {
for (e, mut life) in query {
life.0.tick(time.delta());
if life.0.just_finished() {
commands.entity(e).despawn();
}
}
}