Extract main.rs
This commit is contained in:
parent
84eb560e43
commit
9be7b102d7
2 changed files with 228 additions and 224 deletions
226
src/lib.rs
Normal file
226
src/lib.rs
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
use std::{
|
||||||
|
f32::consts::PI,
|
||||||
|
hash::{DefaultHasher, Hash, Hasher},
|
||||||
|
ops::Range,
|
||||||
|
};
|
||||||
|
|
||||||
|
use avian2d::{math::Vector, prelude::*};
|
||||||
|
use bevy::{
|
||||||
|
color::palettes::{
|
||||||
|
css::WHITE,
|
||||||
|
tailwind::{LIME_400, RED_400},
|
||||||
|
},
|
||||||
|
input::common_conditions::input_pressed,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use bevy_rand::prelude::{EntropyPlugin, GlobalEntropy, WyRand};
|
||||||
|
use clap::Parser;
|
||||||
|
use rand::Rng;
|
||||||
|
use wyrand::WyRand as LocalRng;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(version, about)]
|
||||||
|
pub struct AppSettings {
|
||||||
|
#[arg(short, long, default_value = "")]
|
||||||
|
seed: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const BALL_COUNT: u8 = 32;
|
||||||
|
const BALL_SIZES: Range<f32> = 10.0..25.0;
|
||||||
|
const DIMENSION_SIZES: Range<f32> = 500.0..2000.0;
|
||||||
|
|
||||||
|
#[derive(Clone, Resource)]
|
||||||
|
struct Seed(u64);
|
||||||
|
|
||||||
|
impl From<String> for Seed {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self(value.parse::<u64>().unwrap_or_else(|_| {
|
||||||
|
let mut state = DefaultHasher::new();
|
||||||
|
value.hash(&mut state);
|
||||||
|
state.finish()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Seed> for [u8; 8] {
|
||||||
|
fn from(value: Seed) -> Self {
|
||||||
|
value.0.to_le_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct PlayableArea(f32, f32);
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct PlayerSize(f32);
|
||||||
|
|
||||||
|
pub fn run_app(settings: AppSettings) -> AppExit {
|
||||||
|
let seed = Seed::from(settings.seed);
|
||||||
|
App::new()
|
||||||
|
.insert_resource(Gravity(Vector::ZERO))
|
||||||
|
.insert_resource(seed.clone())
|
||||||
|
.add_plugins((
|
||||||
|
DefaultPlugins.set(WindowPlugin {
|
||||||
|
primary_window: Window {
|
||||||
|
title: "Distributed physics test".into(),
|
||||||
|
fit_canvas_to_parent: true,
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
PhysicsPlugins::default().with_length_unit(50.0),
|
||||||
|
EntropyPlugin::<WyRand>::with_seed(seed.into()),
|
||||||
|
))
|
||||||
|
.add_systems(
|
||||||
|
Startup,
|
||||||
|
(
|
||||||
|
setup_pseudo_random,
|
||||||
|
setup_ui,
|
||||||
|
(setup_player, setup_balls, setup_walls).after(setup_pseudo_random),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(move_player, quit.run_if(input_pressed(KeyCode::KeyQ))),
|
||||||
|
)
|
||||||
|
.add_systems(PostUpdate, move_camera)
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_pseudo_random(mut commands: Commands, mut rng: GlobalEntropy<WyRand>) {
|
||||||
|
commands.insert_resource(PlayerSize(rng.random_range(BALL_SIZES)));
|
||||||
|
commands.insert_resource(PlayableArea(
|
||||||
|
rng.random_range(DIMENSION_SIZES),
|
||||||
|
rng.random_range(DIMENSION_SIZES),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_ui(mut commands: Commands) {
|
||||||
|
commands.spawn((Name::new("Camera"), Camera2d, IsDefaultUiCamera));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[require(Collider, Mesh2d, MeshMaterial2d<ColorMaterial>, Restitution = Restitution::new(1.0), RigidBody, TransformInterpolation, Transform)]
|
||||||
|
struct GameObject;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[require(GameObject, RigidBody = RigidBody::Dynamic)]
|
||||||
|
struct Ball;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[require(Ball)]
|
||||||
|
struct Player;
|
||||||
|
|
||||||
|
fn setup_player(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
radius: Res<PlayerSize>,
|
||||||
|
) {
|
||||||
|
let circle = Circle::new(radius.0);
|
||||||
|
commands.spawn((
|
||||||
|
Player,
|
||||||
|
Collider::from(circle),
|
||||||
|
Mesh2d(meshes.add(circle)),
|
||||||
|
MeshMaterial2d(materials.add(Color::from(LIME_400))),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_balls(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
region: Res<PlayableArea>,
|
||||||
|
) {
|
||||||
|
let mut random = LocalRng::new(Default::default());
|
||||||
|
for _ in 0..BALL_COUNT {
|
||||||
|
let circle = Circle::new(random.random_range(BALL_SIZES));
|
||||||
|
commands.spawn((
|
||||||
|
Ball,
|
||||||
|
Collider::from(circle),
|
||||||
|
Mesh2d(meshes.add(circle)),
|
||||||
|
MeshMaterial2d(materials.add(Color::from(RED_400))),
|
||||||
|
Transform::from_xyz(
|
||||||
|
random.random_range(
|
||||||
|
(-region.0 / 2.0 + circle.radius)..(region.0 / 2.0 - circle.radius),
|
||||||
|
),
|
||||||
|
random.random_range(
|
||||||
|
(-region.1 / 2.0 + circle.radius)..(region.1 / 2.0 - circle.radius),
|
||||||
|
),
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[require(GameObject, RigidBody = RigidBody::Static)]
|
||||||
|
struct Wall;
|
||||||
|
|
||||||
|
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((
|
||||||
|
Wall,
|
||||||
|
Collider::rectangle(length, thickness),
|
||||||
|
Mesh2d(meshes.add(Rectangle::new(length, thickness))),
|
||||||
|
MeshMaterial2d(materials.add(Color::from(WHITE))),
|
||||||
|
transform,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_player(
|
||||||
|
time: Res<Time>,
|
||||||
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
|
mut velocity: Single<&mut LinearVelocity, With<Player>>,
|
||||||
|
) -> Result {
|
||||||
|
let acceleration = 500.0;
|
||||||
|
|
||||||
|
let delta_time = time.delta_secs();
|
||||||
|
|
||||||
|
if keyboard_input.any_pressed([KeyCode::KeyW, KeyCode::ArrowUp]) {
|
||||||
|
velocity.y += acceleration * delta_time;
|
||||||
|
}
|
||||||
|
if keyboard_input.any_pressed([KeyCode::KeyS, KeyCode::ArrowDown]) {
|
||||||
|
velocity.y -= acceleration * delta_time;
|
||||||
|
}
|
||||||
|
if keyboard_input.any_pressed([KeyCode::KeyA, KeyCode::ArrowLeft]) {
|
||||||
|
velocity.x -= acceleration * delta_time;
|
||||||
|
}
|
||||||
|
if keyboard_input.any_pressed([KeyCode::KeyD, KeyCode::ArrowRight]) {
|
||||||
|
velocity.x += acceleration * delta_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quit(mut exit: EventWriter<AppExit>) {
|
||||||
|
exit.write(AppExit::Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_camera(
|
||||||
|
mut camera: Single<&mut Transform, (Without<Player>, With<IsDefaultUiCamera>)>,
|
||||||
|
player: Single<&Transform, (With<Player>, Without<IsDefaultUiCamera>)>,
|
||||||
|
) {
|
||||||
|
camera.translation = camera.translation.lerp(player.translation, 0.05);
|
||||||
|
}
|
226
src/main.rs
226
src/main.rs
|
@ -1,230 +1,8 @@
|
||||||
use std::{
|
use bevy::prelude::AppExit;
|
||||||
f32::consts::PI,
|
|
||||||
hash::{DefaultHasher, Hash, Hasher},
|
|
||||||
ops::Range,
|
|
||||||
};
|
|
||||||
|
|
||||||
use avian2d::{math::Vector, prelude::*};
|
|
||||||
use bevy::{
|
|
||||||
color::palettes::{
|
|
||||||
css::WHITE,
|
|
||||||
tailwind::{LIME_400, RED_400},
|
|
||||||
},
|
|
||||||
input::common_conditions::input_pressed,
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use bevy_rand::prelude::{EntropyPlugin, GlobalEntropy, WyRand};
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use rand::Rng;
|
|
||||||
use wyrand::WyRand as LocalRng;
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
use distributed_physics_test::{AppSettings, run_app};
|
||||||
#[command(version, about)]
|
|
||||||
struct AppSettings {
|
|
||||||
#[arg(short, long, default_value = "")]
|
|
||||||
seed: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> AppExit {
|
fn main() -> AppExit {
|
||||||
run_app(AppSettings::parse())
|
run_app(AppSettings::parse())
|
||||||
}
|
}
|
||||||
|
|
||||||
const BALL_COUNT: u8 = 32;
|
|
||||||
const BALL_SIZES: Range<f32> = 10.0..25.0;
|
|
||||||
const DIMENSION_SIZES: Range<f32> = 500.0..2000.0;
|
|
||||||
|
|
||||||
#[derive(Clone, Resource)]
|
|
||||||
struct Seed(u64);
|
|
||||||
|
|
||||||
impl From<String> for Seed {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
Self(value.parse::<u64>().unwrap_or_else(|_| {
|
|
||||||
let mut state = DefaultHasher::new();
|
|
||||||
value.hash(&mut state);
|
|
||||||
state.finish()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Seed> for [u8; 8] {
|
|
||||||
fn from(value: Seed) -> Self {
|
|
||||||
value.0.to_le_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
struct PlayableArea(f32, f32);
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
struct PlayerSize(f32);
|
|
||||||
|
|
||||||
fn run_app(settings: AppSettings) -> AppExit {
|
|
||||||
let seed = Seed::from(settings.seed);
|
|
||||||
App::new()
|
|
||||||
.insert_resource(Gravity(Vector::ZERO))
|
|
||||||
.insert_resource(seed.clone())
|
|
||||||
.add_plugins((
|
|
||||||
DefaultPlugins.set(WindowPlugin {
|
|
||||||
primary_window: Window {
|
|
||||||
title: "Distributed physics test".into(),
|
|
||||||
fit_canvas_to_parent: true,
|
|
||||||
..default()
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
PhysicsPlugins::default().with_length_unit(50.0),
|
|
||||||
EntropyPlugin::<WyRand>::with_seed(seed.into()),
|
|
||||||
))
|
|
||||||
.add_systems(
|
|
||||||
Startup,
|
|
||||||
(
|
|
||||||
setup_pseudo_random,
|
|
||||||
setup_ui,
|
|
||||||
(setup_player, setup_balls, setup_walls).after(setup_pseudo_random),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
Update,
|
|
||||||
(move_player, quit.run_if(input_pressed(KeyCode::KeyQ))),
|
|
||||||
)
|
|
||||||
.add_systems(PostUpdate, move_camera)
|
|
||||||
.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_pseudo_random(mut commands: Commands, mut rng: GlobalEntropy<WyRand>) {
|
|
||||||
commands.insert_resource(PlayerSize(rng.random_range(BALL_SIZES)));
|
|
||||||
commands.insert_resource(PlayableArea(
|
|
||||||
rng.random_range(DIMENSION_SIZES),
|
|
||||||
rng.random_range(DIMENSION_SIZES),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_ui(mut commands: Commands) {
|
|
||||||
commands.spawn((Name::new("Camera"), Camera2d, IsDefaultUiCamera));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
#[require(Collider, Mesh2d, MeshMaterial2d<ColorMaterial>, Restitution = Restitution::new(1.0), RigidBody, TransformInterpolation, Transform)]
|
|
||||||
struct GameObject;
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
#[require(GameObject, RigidBody = RigidBody::Dynamic)]
|
|
||||||
struct Ball;
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
#[require(Ball)]
|
|
||||||
struct Player;
|
|
||||||
|
|
||||||
fn setup_player(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
radius: Res<PlayerSize>,
|
|
||||||
) {
|
|
||||||
let circle = Circle::new(radius.0);
|
|
||||||
commands.spawn((
|
|
||||||
Player,
|
|
||||||
Collider::from(circle),
|
|
||||||
Mesh2d(meshes.add(circle)),
|
|
||||||
MeshMaterial2d(materials.add(Color::from(LIME_400))),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_balls(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
region: Res<PlayableArea>,
|
|
||||||
) {
|
|
||||||
let mut random = LocalRng::new(Default::default());
|
|
||||||
for _ in 0..BALL_COUNT {
|
|
||||||
let circle = Circle::new(random.random_range(BALL_SIZES));
|
|
||||||
commands.spawn((
|
|
||||||
Ball,
|
|
||||||
Collider::from(circle),
|
|
||||||
Mesh2d(meshes.add(circle)),
|
|
||||||
MeshMaterial2d(materials.add(Color::from(RED_400))),
|
|
||||||
Transform::from_xyz(
|
|
||||||
random.random_range(
|
|
||||||
(-region.0 / 2.0 + circle.radius)..(region.0 / 2.0 - circle.radius),
|
|
||||||
),
|
|
||||||
random.random_range(
|
|
||||||
(-region.1 / 2.0 + circle.radius)..(region.1 / 2.0 - circle.radius),
|
|
||||||
),
|
|
||||||
0.0,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
#[require(GameObject, RigidBody = RigidBody::Static)]
|
|
||||||
struct Wall;
|
|
||||||
|
|
||||||
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((
|
|
||||||
Wall,
|
|
||||||
Collider::rectangle(length, thickness),
|
|
||||||
Mesh2d(meshes.add(Rectangle::new(length, thickness))),
|
|
||||||
MeshMaterial2d(materials.add(Color::from(WHITE))),
|
|
||||||
transform,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_player(
|
|
||||||
time: Res<Time>,
|
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
|
||||||
mut velocity: Single<&mut LinearVelocity, With<Player>>,
|
|
||||||
) -> Result {
|
|
||||||
let acceleration = 500.0;
|
|
||||||
|
|
||||||
let delta_time = time.delta_secs();
|
|
||||||
|
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyW, KeyCode::ArrowUp]) {
|
|
||||||
velocity.y += acceleration * delta_time;
|
|
||||||
}
|
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyS, KeyCode::ArrowDown]) {
|
|
||||||
velocity.y -= acceleration * delta_time;
|
|
||||||
}
|
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyA, KeyCode::ArrowLeft]) {
|
|
||||||
velocity.x -= acceleration * delta_time;
|
|
||||||
}
|
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyD, KeyCode::ArrowRight]) {
|
|
||||||
velocity.x += acceleration * delta_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quit(mut exit: EventWriter<AppExit>) {
|
|
||||||
exit.write(AppExit::Success);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_camera(
|
|
||||||
mut camera: Single<&mut Transform, (Without<Player>, With<IsDefaultUiCamera>)>,
|
|
||||||
player: Single<&Transform, (With<Player>, Without<IsDefaultUiCamera>)>,
|
|
||||||
) {
|
|
||||||
camera.translation = camera.translation.lerp(player.translation, 0.05);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue