2 Commits

Author SHA1 Message Date
2b93654491 Randomly assign asteroid spawning positions
All checks were successful
Basic checks / Basic build-and-test supertask (push) Successful in 6m23s
I need to close the circle down to touch the corners of the play area,
but this demonstrates the principle.

Next, I need to generate a velocity and "fix" it so that the asteroid
crosses through the viewport. I left a TODO about this, which I think
will work well enough. Although it might allow for some asteroids to
slip past, or bias the density in a funny way.

Oh well, it's just an Asteroids game.
2025-07-29 16:31:35 -05:00
c80ada4aa6 Add "rand" crate, store an RNG in AsteroidSpawner 2025-07-29 13:32:26 -05:00
3 changed files with 41 additions and 6 deletions

View File

@@ -6,3 +6,4 @@ edition = "2021"
[dependencies] [dependencies]
bevy = { version = "0.16", features = ["dynamic_linking"] } bevy = { version = "0.16", features = ["dynamic_linking"] }
bevy-inspector-egui = "0.32.0" bevy-inspector-egui = "0.32.0"
rand = "0.9.2"

View File

@@ -1,10 +1,11 @@
use rand::{Rng, SeedableRng};
use std::time::Duration; use std::time::Duration;
/// 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::prelude::*; use bevy::prelude::*;
use crate::{GameAssets, Position, Rotation, Velocity}; use crate::{GameAssets, Position, Rotation, Velocity, WorldSize};
#[derive(Component, Deref, DerefMut)] #[derive(Component, Deref, DerefMut)]
pub struct Asteroid(AsteroidSize); pub struct Asteroid(AsteroidSize);
@@ -17,6 +18,7 @@ pub enum AsteroidSize {
#[derive(Resource)] #[derive(Resource)]
pub struct AsteroidSpawner { pub struct AsteroidSpawner {
rng: std::sync::Mutex<rand::rngs::StdRng>,
timer: Timer, timer: Timer,
// TODO: Configurables? // TODO: Configurables?
// - interval // - interval
@@ -27,6 +29,7 @@ pub struct AsteroidSpawner {
impl AsteroidSpawner { impl AsteroidSpawner {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
rng: std::sync::Mutex::new(rand::rngs::StdRng::from_seed(crate::config::RNG_SEED)),
timer: Timer::new(Duration::from_secs(3), TimerMode::Repeating), timer: Timer::new(Duration::from_secs(3), TimerMode::Repeating),
} }
} }
@@ -45,14 +48,43 @@ pub fn tick_asteroid_manager(
mut events: EventWriter<SpawnAsteroid>, mut events: EventWriter<SpawnAsteroid>,
mut spawner: ResMut<AsteroidSpawner>, mut spawner: ResMut<AsteroidSpawner>,
time: Res<Time>, time: Res<Time>,
play_area: Res<WorldSize>,
) { ) {
spawner.timer.tick(time.delta()); spawner.timer.tick(time.delta());
if spawner.timer.just_finished() { if spawner.timer.just_finished() {
events.write(SpawnAsteroid { let mut rng = spawner
pos: Vec2::ZERO, .rng
vel: Vec2::new(0.0, 40.0), .lock()
size: AsteroidSize::Small, .expect("Expected to acquire lock on the AsteroidSpawner's RNG field.");
});
// Use polar coordinate to decide where the asteroid will spawn
// Theta will be random between 0 to 2pi
let spawn_angle = rng.random_range(0.0..(std::f32::consts::PI * 2.0));
// Rho will be the radius of a circle bordering the viewport, multiplied by 1.2
// TODO: Use view diagonal to get a minimally sized circle around the play area
let spawn_distance = play_area.width.max(play_area.height) / 2.0;
// Convert polar to Cartesian, use as position
let pos = Vec2::new(
spawn_distance * spawn_angle.cos(),
spawn_distance * spawn_angle.sin(),
);
// TODO: Assign velocity such that asteroids will (probably) cross the viewport
// Right now, I'm thinking I can use the opposite signs attached to the position Vec components.
// pos.x == -100, then vel.x = + <random>
// pos.x == 100, then vel.x = - <random>
// etc,
let vel = Vec2::new(rng.random_range(-10.0..10.0), rng.random_range(-10.0..10.0));
let size = match rng.random_range(0..=2) {
0 => AsteroidSize::Small,
1 => AsteroidSize::Medium,
2 => AsteroidSize::Large,
_ => unreachable!(),
};
events.write(SpawnAsteroid { pos, vel, size });
} }
} }

View File

@@ -16,3 +16,5 @@ pub(crate) const ASTEROID_SMALL_COLOR: Color = Color::srgb(1.0, 0., 0.);
pub(crate) const SHIP_THRUST: f32 = 1.0; pub(crate) const SHIP_THRUST: f32 = 1.0;
pub(crate) const SHIP_ROTATION: f32 = 0.1; // +/- rotation speed in... radians per frame pub(crate) const SHIP_ROTATION: f32 = 0.1; // +/- rotation speed in... radians per frame
pub const RNG_SEED: [u8; 32] = *b"12345678909876543210123456789098";