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.
This commit is contained in:
2025-07-29 16:31:35 -05:00
parent c80ada4aa6
commit 2b93654491

View File

@@ -1,11 +1,11 @@
use rand::{Rng, SeedableRng};
use std::time::Duration; use std::time::Duration;
use rand::SeedableRng;
/// 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);
@@ -48,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 });
} }
} }