This commit is contained in:
nora 2023-09-16 23:03:53 +02:00
parent 07f17e5e02
commit aa1b983764
4 changed files with 198 additions and 38 deletions

22
Cargo.lock generated
View file

@ -294,7 +294,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e71a9143ac21bed247c30129399af8be170309e7ff5983a1bd37e87d3da520"
dependencies = [
"bevy_dylib",
"bevy_internal",
]
@ -456,15 +455,6 @@ dependencies = [
"sysinfo",
]
[[package]]
name = "bevy_dylib"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2107d1e8f3d5320ae02b3bf4b2b98c078f225a78a93b01fa29d619bc170f2d9b"
dependencies = [
"bevy_internal",
]
[[package]]
name = "bevy_ecs"
version = "0.11.2"
@ -2612,6 +2602,14 @@ dependencies = [
"redox_syscall",
]
[[package]]
name = "orbital"
version = "0.1.0"
source = "git+https://github.com/oli-obk/solar_sailors.git?rev=2fabdd044f0f362595494dcad5102c50ae9572f7#2fabdd044f0f362595494dcad5102c50ae9572f7"
dependencies = [
"tracing",
]
[[package]]
name = "overload"
version = "0.1.1"
@ -3069,8 +3067,12 @@ dependencies = [
name = "spaceflight"
version = "0.1.0"
dependencies = [
"ahash 0.8.3",
"bevy",
"bevy_rapier3d",
"glam",
"indexmap 2.0.0",
"orbital",
]
[[package]]

View file

@ -12,8 +12,12 @@ opt-level = 1
opt-level = 3
[dependencies]
bevy = { version = "0.11.2", features = ["dynamic_linking"] }
ahash = "0.8.3"
bevy = { version = "0.11.2", features = [] }
bevy_rapier3d = { version = "0.22.0", features = [
"simd-stable",
"debug-render-3d",
] }
glam = { version = "0.24.1", features = ["debug-glam-assert"] }
indexmap = "2.0.0"
orbital = { git = "https://github.com/oli-obk/solar_sailors.git", rev = "2fabdd044f0f362595494dcad5102c50ae9572f7" }

35
src/forces.rs Normal file
View file

@ -0,0 +1,35 @@
use std::any::TypeId;
use bevy::prelude::*;
use bevy_rapier3d::prelude::ExternalForce;
use indexmap::IndexMap;
#[derive(Component, Default)]
pub struct ExternalForceSet {
forces: IndexMap<TypeId, ExternalForce, ahash::RandomState>,
}
impl ExternalForceSet {
pub fn get<T: 'static>(&self) -> ExternalForce {
self.forces
.get(&TypeId::of::<T>())
.copied()
.unwrap_or_default()
}
pub fn set<T: 'static>(&mut self, force: ExternalForce) {
self.forces.insert(TypeId::of::<T>(), force);
}
fn combine(&self) -> ExternalForce {
self.forces
.values()
.fold(ExternalForce::default(), |f1, &f2| f1 + f2)
}
}
pub fn update_external_forces(mut query: Query<(&mut ExternalForce, &ExternalForceSet)>) {
for (mut force, forces) in &mut query {
*force = forces.combine();
}
}

View file

@ -1,14 +1,20 @@
//! A simple 3D scene with light shining over a cube sitting on a plane.
mod forces;
use bevy::{
audio::PlaybackMode,
input::mouse::{MouseMotion, MouseWheel},
prelude::*,
window::PrimaryWindow,
window::{CursorGrabMode, PrimaryWindow},
};
use bevy_rapier3d::prelude::*;
use forces::ExternalForceSet;
use crate::forces::update_external_forces;
fn main() {
dbg!(orbital::Orbit::from_pos_dir(42000.0, 0.0, 0.0, 3074.0));
return;
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
@ -17,9 +23,11 @@ fn main() {
.add_systems(
Update,
(
update_external_forces,
fire_thrusters,
orbit_camera,
apply_gravity,
apply_gravity.before(update_external_forces),
debug_spaceship_orbit,
bevy::window::close_on_esc,
),
)
@ -34,18 +42,14 @@ struct SpaceshipBundle {
body: RigidBody,
collider: Collider,
restitution: Restitution,
mass: Mass,
thrusters: Thrusters,
thruster_force: ExternalForce,
forces: ExternalForceSet,
}
#[derive(Component)]
struct Spaceship;
/// Mass in kg.
#[derive(Component)]
struct Mass(f32);
#[derive(Component)]
struct Thrusters {
/// Strength in some units
@ -53,7 +57,7 @@ struct Thrusters {
}
#[derive(Component)]
struct HasGravity {
struct GravityAttractor {
mass: f32,
}
@ -68,11 +72,13 @@ struct ThrusterSound;
fn fire_thrusters(
mut commands: Commands,
keyboard_input: Res<Input<KeyCode>>,
mut query: Query<(&mut ExternalForce, &Thrusters)>,
mut query: Query<(&mut ExternalForceSet, &Transform, &Thrusters)>,
sound_query: Query<&AudioSink, With<ThrusterSound>>,
asset_server: Res<AssetServer>,
) {
let (mut force, thrusters) = query.single_mut();
struct ThrusterForce;
let (mut force_set, transform, thrusters) = query.single_mut();
if keyboard_input.just_pressed(KeyCode::Space) {
if let Ok(sound) = sound_query.get_single() {
@ -89,23 +95,127 @@ fn fire_thrusters(
ThrusterSound,
));
}
}
if keyboard_input.just_pressed(KeyCode::Space) {
force.force = Vec3 {
x: 0.0,
y: thrusters.strength,
z: 0.0,
};
} else if keyboard_input.just_released(KeyCode::Space) {
if let Ok(sound) = sound_query.get_single() {
sound.pause();
}
}
let rotation = Mat3::from_quat(transform.rotation);
let mut force = force_set.get::<ThrusterForce>();
if keyboard_input.pressed(KeyCode::Space) {
force.force = rotation.mul_vec3(Vec3::new(0.0, thrusters.strength, 0.0));
} else {
force.force = Vec3::ZERO;
}
let torque = 0.2;
let keybinds = [
(KeyCode::W, Vec3::new(torque, 0.0, 0.0)),
(KeyCode::S, Vec3::new(-torque, -0.0, 0.0)),
(KeyCode::Q, Vec3::new(0.0, torque, 0.0)),
(KeyCode::E, Vec3::new(0.0, -torque, 0.0)),
(KeyCode::A, Vec3::new(0.0, 0.0, torque)),
(KeyCode::D, Vec3::new(0.0, -0.0, -torque)),
];
let mut any_pressed = false;
for (bind, vec) in keybinds {
if keyboard_input.pressed(bind) {
any_pressed = true;
force.torque = rotation.mul_vec3(vec);
}
}
if !any_pressed {
force.torque = Vec3::ZERO;
}
force_set.set::<ThrusterForce>(force);
}
fn apply_gravity(
mut query: Query<(&mut ExternalForceSet, &Transform), With<Spaceship>>,
body_query: Query<(&GravityAttractor, &Transform), Without<Spaceship>>,
) {
struct GravityForce;
const G: f64 = 1.0;
let (mut ship_forces, ship_transform) = query.single_mut();
for (gravity, body_transform) in &body_query {
let distance = ship_transform
.translation
.distance(body_transform.translation) as f64;
let fg = (G * (gravity.mass as f64)) / (distance * distance);
let direction = (body_transform.translation - ship_transform.translation).normalize();
let fg = ExternalForce {
force: direction * (fg as f32),
torque: Vec3::ZERO,
};
ship_forces.set::<GravityForce>(fg);
}
}
fn apply_gravity(query: Query<&mut ExternalForce, With<Spaceship>>) {}
fn debug_spaceship_orbit(
query: Query<(&Transform, &Velocity), With<Spaceship>>,
body_query: Query<&Transform, (With<GravityAttractor>, Without<Spaceship>)>,
mut gizmos: Gizmos,
) {
let (ship_transform, &v) = query.single();
let ship_pos = ship_transform.translation;
let body_transform = body_query.single();
let body_pos = body_transform.translation;
let body_rotation = body_transform.rotation;
let body_axis = body_rotation * Vec3::Y;
gizmos.ray(body_pos, body_axis * 150.0, Color::GOLD);
gizmos.ray(body_pos, -body_axis * 150.0, Color::GOLD);
let velocity = v.linvel;
let translation = ship_pos - body_pos;
let orbital_plane_normal = velocity.cross(translation).normalize_or_zero() * 10.0;
gizmos.ray(ship_pos, orbital_plane_normal, Color::PINK);
let orbital_plane_rot = Quat::from_rotation_arc(
orbital_plane_normal.try_normalize().unwrap_or(Vec3::X),
Vec3::Y,
);
let rotated_vel = orbital_plane_rot * velocity;
let rotated_pos = orbital_plane_rot * translation;
dbg!((rotated_pos, rotated_vel));
gizmos.ray(body_pos, rotated_pos, Color::FUCHSIA);
gizmos.ray(
body_pos,
rotated_vel.normalize_or_zero() * 120.0,
Color::OLIVE,
);
if true && (rotated_pos.length() > 0.0 && rotated_vel.length() > 0.1 && rotated_vel.z > 0.1) {
let orbit = orbital::Orbit::from_pos_dir(
rotated_pos.x.into(),
rotated_pos.z.into(),
rotated_vel.x.into(),
rotated_vel.z.into(),
);
dbg!(orbit);
}
gizmos.ray_gradient(ship_pos, velocity, Color::RED, Color::GREEN);
gizmos.ray_gradient(ship_pos, translation, Color::BLUE, Color::GREEN);
gizmos.line(body_transform.translation, ship_pos, Color::WHITE);
}
// adapted from https://bevy-cheatbook.github.io/cookbook/pan-orbit-camera.html
fn orbit_camera(
@ -143,13 +253,14 @@ fn orbit_camera(
/// set up a simple 3D scene
fn setup(
mut windows: Query<&mut Window>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let mut rapier = RapierConfiguration::default();
// We ain't a normal game, we do our own gravity.
rapier.gravity = Vec3::new(0.0, -0.5, 0.0);
rapier.gravity = Vec3::new(0.0, 0.0, 0.0);
commands.insert_resource(rapier);
commands.spawn(PlanetBundle::new(
@ -157,7 +268,7 @@ fn setup(
&mut materials,
Transform::from_xyz(0.0, -100.0, 0.0),
100.0,
0.0,
5000.0,
Color::rgb(0.2, 0.8, 0.5),
));
@ -185,6 +296,10 @@ fn setup(
radius: camera_translation.length(),
},
));
let mut window = windows.single_mut();
// window.cursor.visible = false;
window.cursor.grab_mode = CursorGrabMode::Locked;
}
impl SpaceshipBundle {
@ -192,7 +307,7 @@ impl SpaceshipBundle {
let height = 4.0;
let width = 0.5;
Self {
SpaceshipBundle {
ship_marker: Spaceship,
model: PbrBundle {
mesh: meshes.add(Mesh::from(shape::Box::new(width, height, width))),
@ -205,10 +320,13 @@ impl SpaceshipBundle {
..default()
},
vel: Velocity {
linvel: Vec3::ZERO,
linvel: Vec3 {
x: 100.0,
y: 100.0,
z: 100.0,
},
angvel: Vec3::ZERO,
},
mass: Mass(1000.0),
body: RigidBody::Dynamic,
collider: Collider::cuboid(width / 2.0, height / 2.0, width / 2.0),
restitution: Restitution::coefficient(0.1),
@ -217,6 +335,7 @@ impl SpaceshipBundle {
force: Vec3::new(0.0, -0.5, 0.0), // gravity
torque: Vec3::ZERO,
},
forces: ExternalForceSet::default(),
}
}
}
@ -225,7 +344,7 @@ impl SpaceshipBundle {
struct PlanetBundle {
mesh: PbrBundle,
coll: Collider,
gravity: HasGravity,
gravity: GravityAttractor,
}
impl PlanetBundle {
@ -252,7 +371,7 @@ impl PlanetBundle {
..default()
},
coll: Collider::ball(radius),
gravity: HasGravity { mass },
gravity: GravityAttractor { mass },
}
}
}