diff --git a/src/config.rs b/src/config.rs index c8a2fbe..6e0fc62 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,9 +10,12 @@ pub(crate) const PLAYER_SHIP_COLOR: Color = Color::srgb(1.0, 1.0, 1.0); pub(crate) const SHIP_THRUSTER_COLOR_ACTIVE: Color = Color::srgb(1.0, 0.2, 0.2); pub(crate) const SHIP_THRUSTER_COLOR_INACTIVE: Color = Color::srgb(0.5, 0.5, 0.5); pub(crate) const ASTEROID_SMALL_COLOR: Color = Color::srgb(1.0, 0., 0.); +pub(crate) const BULLET_COLOR: Color = Color::srgb(0.0, 0.1, 0.9); // TODO: asteroid medium & large 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 BULLET_SPEED: f32 = 150.0; + pub const RNG_SEED: [u8; 32] = *b"12345678909876543210123456789098"; diff --git a/src/event.rs b/src/event.rs index 40252d9..7810c6f 100644 --- a/src/event.rs +++ b/src/event.rs @@ -12,3 +12,10 @@ pub(crate) struct AsteroidDestroy(pub Entity); // TODO: BulletDestroy // Which depends on the still-pending Bullet component creation. + +/// Signals that a particular bullet has been destroyed. +/// Used to despawn the bullet after it strikes an Asteroid. +/// +/// TODO: Maybe use it for lifetime expiration (which is also a TODO item). +#[derive(Event)] +pub(crate) struct BulletDestroy(pub Entity); diff --git a/src/lib.rs b/src/lib.rs index 82e590a..58571fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,8 +8,9 @@ mod title_screen; use crate::asteroids::{Asteroid, AsteroidSpawner}; use crate::config::{ - ASTEROID_SMALL_COLOR, BACKGROUND_COLOR, PLAYER_SHIP_COLOR, SHIP_ROTATION, SHIP_THRUST, - SHIP_THRUSTER_COLOR_ACTIVE, SHIP_THRUSTER_COLOR_INACTIVE, WINDOW_SIZE, + ASTEROID_SMALL_COLOR, BACKGROUND_COLOR, BULLET_COLOR, BULLET_SPEED, PLAYER_SHIP_COLOR, + SHIP_ROTATION, SHIP_THRUST, SHIP_THRUSTER_COLOR_ACTIVE, SHIP_THRUSTER_COLOR_INACTIVE, + WINDOW_SIZE, }; use crate::physics::AngularVelocity; use crate::ship::Ship; @@ -50,6 +51,7 @@ impl Plugin for AsteroidPlugin { ( input_ship_thruster, input_ship_rotation, + input_ship_shoot, physics::wrap_entities, asteroids::tick_asteroid_manager, asteroids::spawn_asteroid.after(asteroids::tick_asteroid_manager), @@ -163,8 +165,8 @@ struct WorldSize { #[derive(Resource)] struct GameAssets { - meshes: [Handle; 4], - materials: [Handle; 6], + meshes: [Handle; 5], + materials: [Handle; 7], } impl GameAssets { @@ -199,6 +201,10 @@ impl GameAssets { fn asteroid_large(&self) -> (Handle, Handle) { (self.meshes[3].clone(), self.materials[3].clone()) } + + fn bullet(&self) -> (Handle, Handle) { + (self.meshes[4].clone(), self.materials[6].clone()) + } } impl FromWorld for GameAssets { @@ -213,6 +219,7 @@ impl FromWorld for GameAssets { world_meshes.add(Circle::new(10.0)), world_meshes.add(Circle::new(20.0)), world_meshes.add(Circle::new(40.0)), + world_meshes.add(Circle::new(0.2)), ]; let mut world_materials = world.resource_mut::>(); let materials = [ @@ -223,6 +230,7 @@ impl FromWorld for GameAssets { // TODO: asteroid medium and large colors world_materials.add(ASTEROID_SMALL_COLOR), world_materials.add(ASTEROID_SMALL_COLOR), + world_materials.add(BULLET_COLOR), ]; GameAssets { meshes, materials } } @@ -287,6 +295,35 @@ fn input_ship_rotation( } } +fn input_ship_shoot( + keyboard_input: Res>, + ship: Single<(&Transform, &physics::Velocity), With>, + game_assets: Res, + mut commands: Commands, +) { + let (ship_pos, ship_vel) = *ship; + + // Derive bullet velocity, add to the ship's velocity + let bullet_vel = (ship_pos.rotation * Vec3::X).xy() * BULLET_SPEED; + let bullet_vel = bullet_vel + ship_vel.0; + + // TODO: create a timer for the gun fire rate. + // For now, spawn one for each press of the spacebar. + if keyboard_input.just_pressed(KeyCode::Space) { + commands.spawn(( + ship::Bullet, + Collider::ball(0.2), + Sensor, + ActiveEvents::COLLISION_EVENTS, + ActiveCollisionTypes::STATIC_STATIC, + physics::Velocity(bullet_vel), + Mesh2d(game_assets.bullet().0), + MeshMaterial2d(game_assets.bullet().1), + ship_pos.clone(), // clone ship transform + )); + } +} + fn spawn_ui(mut commands: Commands, score: Res, lives: Res) { commands.spawn(( Text::new(format!("Score: {score:?} | Lives: {lives:?}")), diff --git a/src/physics.rs b/src/physics.rs index 6186a76..dabe837 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -5,7 +5,7 @@ use crate::WorldSize; use bevy::prelude::*; -#[derive(Component)] +#[derive(Clone, Component)] pub(crate) struct Velocity(pub(crate) bevy::math::Vec2); #[derive(Component)] diff --git a/src/ship.rs b/src/ship.rs index b49a6e2..b2eeda2 100644 --- a/src/ship.rs +++ b/src/ship.rs @@ -9,6 +9,9 @@ use bevy_rapier2d::prelude::*; #[derive(Component)] pub struct Ship; +#[derive(Component)] +pub struct Bullet; + pub fn spawn_player(mut commands: Commands, game_assets: Res) { commands .spawn((