use std::{f32::consts::PI, ops::Range}; use avian2d::prelude::*; use bevy::{ color::palettes::{ css::WHITE, tailwind::{LIME_400, RED_400}, }, prelude::*, }; use bevy_rand::prelude::{GlobalEntropy, WyRand}; use rand::Rng as _; use super::{ objects::{Ball, Player, Wall}, rng::thread_rng, }; const BALL_COUNT: u8 = 32; const BALL_SIZES: Range = 10.0..25.0; const DIMENSION_SIZES: Range = 500.0..2000.0; /// The size of the playable area (x, y) #[derive(Resource)] pub struct PlayableArea(f32, f32); /// The size of the player character #[derive(Resource)] pub struct PlayerSize(f32); /// Initialize deterministic values pub fn setup_pseudo_random(mut commands: Commands, mut rng: GlobalEntropy) { commands.insert_resource(PlayerSize(rng.random_range(BALL_SIZES))); commands.insert_resource(PlayableArea( rng.random_range(DIMENSION_SIZES), rng.random_range(DIMENSION_SIZES), )); } pub fn setup_ui(mut commands: Commands) { commands.spawn((Name::new("Camera"), Camera2d, IsDefaultUiCamera)); } /// Create the playable character pub fn setup_player( mut commands: Commands, mut materials: ResMut>, mut meshes: ResMut>, radius: Res, ) { let circle = Circle::new(radius.0); commands.spawn(( Name::new("Player"), Player, Collider::from(circle), Mesh2d(meshes.add(circle)), MeshMaterial2d(materials.add(Color::from(LIME_400))), )); } /// Create a random distribution of balls in the playable area pub fn setup_balls( mut commands: Commands, mut materials: ResMut>, mut meshes: ResMut>, region: Res, ) { let mut random = thread_rng(); for i in 0..BALL_COUNT { let circle = Circle::new(random.random_range(BALL_SIZES)); commands.spawn(( Name::new(format!("Ball[{i}]")), Ball, Collider::from(circle), Mesh2d(meshes.add(circle)), MeshMaterial2d(materials.add(Color::from(RED_400))), Transform::from_xyz( random.random::() * (region.0 - 2.0 * circle.radius) + circle.radius, random.random::() * (region.1 - 2.0 * circle.radius) + circle.radius, 0.0, ), )); } } /// Create the 4 walls that enclose the playable area pub fn setup_walls( mut commands: Commands, mut materials: ResMut>, mut meshes: ResMut>, region: Res, ) { let thickness = 20.0; for i in 0..4 { let (offset, length) = if i % 2 == 0 { (region.0, region.1 + thickness) } else { (region.1, region.0 + thickness) }; let mut transform = Transform::from_xyz(0.0, offset / 2.0, 0.0); transform.rotate_around( Vec3::ZERO, Quat::from_rotation_z(((i + 1) as f32) * PI / 2.0), ); commands.spawn(( Name::new(format!("Wall[{i}]")), Wall, Collider::rectangle(length, thickness), Mesh2d(meshes.add(Rectangle::new(length, thickness))), MeshMaterial2d(materials.add(Color::from(WHITE))), transform, )); } }