Преглед на файлове

orbits are elliptical, but still spin out.

john melesky преди 3 месеца
родител
ревизия
9b7930cc55
променени са 1 файла, в които са добавени 253 реда и са изтрити 1 реда
  1. 253 1
      src/main.rs

+ 253 - 1
src/main.rs

@@ -1,3 +1,255 @@
+use bevy::prelude::*;
+use bevy::sprite::MaterialMesh2dBundle;
+use std::time::Duration;
+
+const SUN_SIZE: f32 = 20.;
+
+#[derive(Event, Default)]
+struct PlayBoop;
+
+#[derive(Resource)]
+struct Boop(f32); // frequency in hz
+
+
+#[derive(Component)]
+struct Position(Vec2);
+
+#[derive(Component)]
+struct Velocity(Vec2);
+
+#[derive(Component)]
+struct Size(f32);
+
+#[derive(Component)]
+struct Mass(f32);
+
+#[derive(Component)]
+struct Planet {
+    focus: Position,
+}
+
+impl Planet {
+    fn new(fx:f32, fy:f32) -> Self {
+        Self {
+            focus: Position(Vec2::new(fx, fy)),
+        }
+    }
+}
+
+#[derive(Component)]
+struct Sun;
+
+#[derive(Bundle)]
+struct PlanetBundle {
+    planet: Planet,
+    size: Size,
+    mass: Mass,
+    position: Position,
+}
+
+impl PlanetBundle {
+    fn new(posx:f32, posy:f32, fx:f32, fy:f32) -> Self {
+        Self {
+            planet: Planet::new(fx, fy),
+            size: Size(20.),
+            mass: Mass(200.),
+            position: Position(Vec2::new(posx, posy)),
+        }
+    }
+}
+
+#[derive(Bundle)]
+struct SunBundle {
+    sun: Sun,
+    size: Size,
+    mass: Mass,
+    position: Position
+}
+
+impl SunBundle {
+    fn new(posx:f32, posy:f32) -> Self {
+        Self {
+            sun: Sun,
+            size: Size(2000.),
+            mass: Mass(20_000_000.),
+            position: Position(Vec2::new(posx, posy)),
+        }
+    }
+}
+
+fn spawn_camera(mut commands: Commands) {
+    commands.spawn_empty()
+        .insert(Camera2dBundle::default());
+}
+
+fn spawn_planet(
+    mut commands: Commands,
+    mut meshes: ResMut<Assets<Mesh>>,
+    mut materials: ResMut<Assets<ColorMaterial>>,
+) {
+    println!("Spawning planet!");
+
+    let shape = Mesh::from(Circle::new(5.));
+    let color = ColorMaterial::from(Color::srgb(1., 0.3, 0.3));
+
+    let mesh_handle = meshes.add(shape);
+    let material_handle = materials.add(color);
+
+    commands.spawn((
+        PlanetBundle::new(120., 150.,
+                          50., 0.),
+        MaterialMesh2dBundle {
+            mesh: mesh_handle.into(),
+            material: material_handle,
+            ..default()
+        },
+    ));
+
+    let shape2 = Mesh::from(Circle::new(3.));
+    let color2 = ColorMaterial::from(Color::srgb(0.2, 0.3, 1.));
+    let mesh2 = meshes.add(shape2);
+    let material2 = materials.add(color2);
+
+    commands.spawn((
+        PlanetBundle::new(80., -20.,
+                          10., 30.),
+        MaterialMesh2dBundle {
+            mesh: mesh2.into(),
+            material: material2,
+            ..default()
+        },
+    ));
+}
+
+fn spawn_sun(
+    mut commands: Commands,
+    mut meshes: ResMut<Assets<Mesh>>,
+    mut materials: ResMut<Assets<ColorMaterial>>,
+) {
+    println!("Spawning sun!");
+
+    let shape = Mesh::from(Circle::new(SUN_SIZE));
+    let color = ColorMaterial::from(Color::srgb(0.8, 0.9, 0.3));
+
+    let mesh_handle = meshes.add(shape);
+    let material_handle = materials.add(color);
+
+    commands.spawn((
+        SunBundle::new(0., 0.),
+        MaterialMesh2dBundle {
+            mesh: mesh_handle.into(),
+            material: material_handle,
+            ..default()
+        },
+    ));
+}
+
+
+fn move_planets(
+    time: Res<Time>,
+    mut planets: Query<(&mut Position, &mut Planet)>
+) {
+    for (mut position, mut planet) in &mut planets {
+        // okay
+        //
+        // so the line segment from sun to point
+        // and the line segment from focus to point
+        // converge at point
+        // we want to bisect the angle, then get the
+        // perpendicular
+
+        // xy0, xy1 - sun to point
+        // xy2, xy3 - focus to point
+
+        let x02 = 0. - planet.focus.0.x;
+        let y02 = 0. - planet.focus.0.y;
+        let x10 = position.0.x - 0.;
+        let y10 = position.0.y - 0.;
+        let x32 = position.0.x - planet.focus.0.x;
+        let y32 = position.0.y - planet.focus.0.y;
+
+        let l = y32 * x10 - x32 * y10;
+        // if l low, parallel (drop to perpendicular);
+        let l10 = (x10.powf(2.) + y10.powf(2.)).sqrt();
+        let l32 = (x32.powf(2.) + y32.powf(2.)).sqrt();
+
+        let speedfactor = l32 / l10;
+
+        let ti = (x32 * y02 - y32 * x02) / l;
+        let xi = 0. + ti * x10;
+        let yi = 0. + ti * y10;
+        let xitmp = xi + x10/l10 - x32/l32;
+        let yitmp = yi + y10/l10 - y32/l32;
+        let li = ((xitmp - xi).powf(2.) + (yitmp - yi).powf(2.)).sqrt();
+        let xi2 = xitmp + ((xitmp - xi) / li) * 60. * speedfactor;
+        let yi2 = yitmp + ((yitmp - yi) / li) * 60. * speedfactor;
+
+
+        if (position.0.y > 0.) {
+            position.0.x += (xi2 - xi).abs() * time.delta_seconds();
+        } else {
+            position.0.x -= (xi2 - xi).abs() * time.delta_seconds();
+        }
+
+        if (position.0.x > 0.) {
+            position.0.y -= (yi2 - yi).abs() * time.delta_seconds();
+        } else {
+            position.0.y += (yi2 - yi).abs() * time.delta_seconds();
+        }
+
+    }
+}
+
+
+fn project_positions(
+    mut positionables: Query<(&mut Transform, &Position)>
+) {
+    for (mut transform, position) in &mut positionables {
+        transform.translation = position.0.extend(0.);
+    }
+}
+
+
+fn setup_audio(
+    mut commands: Commands
+) {
+    commands.insert_resource(Boop(440.));
+}
+
+fn play_boop(
+    mut boop_assets: ResMut<Assets<Pitch>>,
+    boop: Res<Boop>,
+    mut events: EventReader<PlayBoop>,
+    mut commands: Commands,
+) {
+    for _ in events.read() {
+        info!("playing pitch with frequency: {}", boop.0);
+        commands.spawn(PitchBundle {
+            source: boop_assets.add(Pitch::new(boop.0, Duration::from_millis(400))),
+            settings: PlaybackSettings::DESPAWN,
+        });
+        info!("number of pitch assets: {}", boop_assets.len());
+    }
+}
+
+
 fn main() {
-    println!("Hello, world!");
+    App::new()
+        .add_plugins(DefaultPlugins)
+        .add_event::<PlayBoop>()
+        .add_systems(Startup,
+                     (
+                         spawn_camera,
+                         spawn_sun,
+                         spawn_planet,
+                         setup_audio,
+                     ))
+        .add_systems(Update,
+                     (
+                         play_boop,
+                         move_planets,
+                         project_positions.after(move_planets)
+                     ),
+        )
+        .run();
 }