Move asteroid spawning & splitting systems
They deal with events, but are directly related to how the Asteroid object interacts with the events, so I'm putting them here.
This commit is contained in:
@@ -1,19 +1,12 @@
|
|||||||
//! This is the module containing all the rock-related things.
|
//! This is the module containing all the rock-related things.
|
||||||
//! Not... not the whole game.
|
//! Not... not the whole game.
|
||||||
|
|
||||||
use bevy_rapier2d::prelude::*;
|
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{WorldSize, events::SpawnAsteroid, objects::AsteroidSize};
|
||||||
GameAssets, Lifetime, WorldSize,
|
|
||||||
config::ASTEROID_LIFETIME,
|
|
||||||
events::{AsteroidDestroy, SpawnAsteroid},
|
|
||||||
objects::{Asteroid, AsteroidSize},
|
|
||||||
physics::Velocity,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct AsteroidSpawner {
|
pub struct AsteroidSpawner {
|
||||||
@@ -84,77 +77,3 @@ pub fn tick_asteroid_manager(
|
|||||||
events.write(SpawnAsteroid { pos, vel, size });
|
events.write(SpawnAsteroid { pos, vel, size });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utility function to spawn a single asteroid of a given type
|
|
||||||
/// TODO: convert to an event listener monitoring for "spawn asteroid" events
|
|
||||||
/// from the `fn tick_asteroid_manager(...)` system.
|
|
||||||
pub fn spawn_asteroid(
|
|
||||||
mut events: EventReader<SpawnAsteroid>,
|
|
||||||
mut commands: Commands,
|
|
||||||
game_assets: Res<GameAssets>,
|
|
||||||
) {
|
|
||||||
for spawn in events.read() {
|
|
||||||
let (mesh, material) = match spawn.size {
|
|
||||||
AsteroidSize::Small => game_assets.asteroid_small(),
|
|
||||||
AsteroidSize::Medium => game_assets.asteroid_medium(),
|
|
||||||
AsteroidSize::Large => game_assets.asteroid_large(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let collider_radius = match spawn.size {
|
|
||||||
AsteroidSize::Small => 10.0,
|
|
||||||
AsteroidSize::Medium => 20.0,
|
|
||||||
AsteroidSize::Large => 40.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Asteroid(spawn.size),
|
|
||||||
Collider::ball(collider_radius),
|
|
||||||
Sensor,
|
|
||||||
Transform::from_translation(spawn.pos.extend(0.0)),
|
|
||||||
Velocity(spawn.vel),
|
|
||||||
Mesh2d(mesh),
|
|
||||||
MeshMaterial2d(material),
|
|
||||||
Lifetime(Timer::from_seconds(ASTEROID_LIFETIME, TimerMode::Once)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ impl Plugin for AsteroidPlugin {
|
|||||||
input_ship_shoot,
|
input_ship_shoot,
|
||||||
physics::wrap_entities,
|
physics::wrap_entities,
|
||||||
asteroids::tick_asteroid_manager,
|
asteroids::tick_asteroid_manager,
|
||||||
asteroids::spawn_asteroid.after(asteroids::tick_asteroid_manager),
|
objects::spawn_asteroid.after(asteroids::tick_asteroid_manager),
|
||||||
asteroids::split_asteroids,
|
objects::split_asteroids,
|
||||||
ship::bullet_impact_listener,
|
ship::bullet_impact_listener,
|
||||||
ship::ship_impact_listener,
|
ship::ship_impact_listener,
|
||||||
collision_listener,
|
collision_listener,
|
||||||
|
|||||||
@@ -3,8 +3,25 @@
|
|||||||
//! Asteroids, the player's ship, and such.
|
//! Asteroids, the player's ship, and such.
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::component::Component,
|
ecs::{
|
||||||
|
component::Component,
|
||||||
|
event::{EventReader, EventWriter},
|
||||||
|
system::{Commands, Query, Res},
|
||||||
|
},
|
||||||
|
math::{Vec2, Vec3Swizzles},
|
||||||
prelude::{Deref, DerefMut},
|
prelude::{Deref, DerefMut},
|
||||||
|
render::mesh::Mesh2d,
|
||||||
|
sprite::MeshMaterial2d,
|
||||||
|
time::{Timer, TimerMode},
|
||||||
|
transform::components::Transform,
|
||||||
|
};
|
||||||
|
use bevy_rapier2d::prelude::{Collider, Sensor};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
GameAssets, Lifetime,
|
||||||
|
config::ASTEROID_LIFETIME,
|
||||||
|
events::{AsteroidDestroy, SpawnAsteroid},
|
||||||
|
physics::Velocity,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Component, Deref, DerefMut)]
|
#[derive(Component, Deref, DerefMut)]
|
||||||
@@ -32,3 +49,75 @@ pub struct Ship;
|
|||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Bullet;
|
pub struct Bullet;
|
||||||
|
|
||||||
|
/// Responds to [`SpawnAsteroid`] events, spawning as specified
|
||||||
|
pub fn spawn_asteroid(
|
||||||
|
mut events: EventReader<SpawnAsteroid>,
|
||||||
|
mut commands: Commands,
|
||||||
|
game_assets: Res<GameAssets>,
|
||||||
|
) {
|
||||||
|
for spawn in events.read() {
|
||||||
|
let (mesh, material) = match spawn.size {
|
||||||
|
AsteroidSize::Small => game_assets.asteroid_small(),
|
||||||
|
AsteroidSize::Medium => game_assets.asteroid_medium(),
|
||||||
|
AsteroidSize::Large => game_assets.asteroid_large(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let collider_radius = match spawn.size {
|
||||||
|
AsteroidSize::Small => 10.0,
|
||||||
|
AsteroidSize::Medium => 20.0,
|
||||||
|
AsteroidSize::Large => 40.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
Asteroid(spawn.size),
|
||||||
|
Collider::ball(collider_radius),
|
||||||
|
Sensor,
|
||||||
|
Transform::from_translation(spawn.pos.extend(0.0)),
|
||||||
|
Velocity(spawn.vel),
|
||||||
|
Mesh2d(mesh),
|
||||||
|
MeshMaterial2d(material),
|
||||||
|
Lifetime(Timer::from_seconds(ASTEROID_LIFETIME, TimerMode::Once)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user