129 lines
3.6 KiB
Rust
129 lines
3.6 KiB
Rust
use std::{f32::consts::PI, ops::Range};
|
|
|
|
use avian2d::prelude::*;
|
|
use bevy::{
|
|
color::palettes::{
|
|
css::WHITE,
|
|
tailwind::{LIME_400, RED_400},
|
|
},
|
|
prelude::*,
|
|
};
|
|
use rand::{Rng as _, SeedableRng};
|
|
use wyrand::WyRand;
|
|
|
|
use crate::AppState;
|
|
|
|
use super::{
|
|
objects::{Ball, Player, Radius, Wall},
|
|
rng::thread_rng,
|
|
seed::Seed,
|
|
};
|
|
|
|
const BALL_COUNT: u8 = 32;
|
|
const BALL_SIZES: Range<f32> = 10.0..25.0;
|
|
const DIMENSION_SIZES: Range<f32> = 500.0..2000.0;
|
|
|
|
pub fn check_for_seed(seed: Option<Res<Seed>>, mut next_state: ResMut<NextState<AppState>>) {
|
|
if seed.is_some() {
|
|
next_state.set(AppState::InGame);
|
|
}
|
|
}
|
|
|
|
/// The size of the playable area (x, y)
|
|
#[derive(Resource)]
|
|
pub struct PlayableArea(f32, f32);
|
|
|
|
/// Initialize deterministic values
|
|
pub fn setup_from_seed(mut commands: Commands, seed: Res<Seed>) {
|
|
let mut rng = WyRand::from_seed((*seed).into());
|
|
commands.insert_resource(PlayableArea(
|
|
rng.random_range(DIMENSION_SIZES),
|
|
rng.random_range(DIMENSION_SIZES),
|
|
));
|
|
}
|
|
|
|
/// I mean, a camera is technically a user interface, I guess
|
|
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<Assets<ColorMaterial>>,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
) {
|
|
let mut random = thread_rng();
|
|
|
|
let radius = random.random_range(BALL_SIZES);
|
|
let circle = Circle::new(radius);
|
|
commands.spawn((
|
|
Name::new("Player"),
|
|
Player,
|
|
Radius(radius),
|
|
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<Assets<ColorMaterial>>,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
region: Res<PlayableArea>,
|
|
) {
|
|
let mut random = thread_rng();
|
|
|
|
for i in 0..BALL_COUNT {
|
|
let radius = random.random_range(BALL_SIZES);
|
|
let circle = Circle::new(radius);
|
|
commands.spawn((
|
|
Name::new(format!("Ball[{i}]")),
|
|
Ball,
|
|
Radius(radius),
|
|
Collider::from(circle),
|
|
Mesh2d(meshes.add(circle)),
|
|
MeshMaterial2d(materials.add(Color::from(RED_400))),
|
|
Transform::from_xyz(
|
|
random.random::<f32>() * (region.0 - 2.0 * radius) + radius - region.0 / 2.0,
|
|
random.random::<f32>() * (region.1 - 2.0 * radius) + radius - region.1 / 2.0,
|
|
0.0,
|
|
),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Create the 4 walls that enclose the playable area
|
|
pub fn setup_walls(
|
|
mut commands: Commands,
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
region: Res<PlayableArea>,
|
|
) {
|
|
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,
|
|
));
|
|
}
|
|
}
|