mirror of
https://github.com/Noratrieb/spaceship.git
synced 2026-01-14 16:35:08 +01:00
forces
This commit is contained in:
parent
07f17e5e02
commit
aa1b983764
4 changed files with 198 additions and 38 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
|
@ -294,7 +294,6 @@ version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18e71a9143ac21bed247c30129399af8be170309e7ff5983a1bd37e87d3da520"
|
checksum = "18e71a9143ac21bed247c30129399af8be170309e7ff5983a1bd37e87d3da520"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_dylib",
|
|
||||||
"bevy_internal",
|
"bevy_internal",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -456,15 +455,6 @@ dependencies = [
|
||||||
"sysinfo",
|
"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]]
|
[[package]]
|
||||||
name = "bevy_ecs"
|
name = "bevy_ecs"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
|
@ -2612,6 +2602,14 @@ dependencies = [
|
||||||
"redox_syscall",
|
"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]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
@ -3069,8 +3067,12 @@ dependencies = [
|
||||||
name = "spaceflight"
|
name = "spaceflight"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash 0.8.3",
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_rapier3d",
|
"bevy_rapier3d",
|
||||||
|
"glam",
|
||||||
|
"indexmap 2.0.0",
|
||||||
|
"orbital",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,12 @@ opt-level = 1
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[dependencies]
|
[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 = [
|
bevy_rapier3d = { version = "0.22.0", features = [
|
||||||
"simd-stable",
|
"simd-stable",
|
||||||
"debug-render-3d",
|
"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
35
src/forces.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
173
src/main.rs
173
src/main.rs
|
|
@ -1,14 +1,20 @@
|
||||||
//! A simple 3D scene with light shining over a cube sitting on a plane.
|
mod forces;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
audio::PlaybackMode,
|
audio::PlaybackMode,
|
||||||
input::mouse::{MouseMotion, MouseWheel},
|
input::mouse::{MouseMotion, MouseWheel},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
window::PrimaryWindow,
|
window::{CursorGrabMode, PrimaryWindow},
|
||||||
};
|
};
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
|
use forces::ExternalForceSet;
|
||||||
|
|
||||||
|
use crate::forces::update_external_forces;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
dbg!(orbital::Orbit::from_pos_dir(42000.0, 0.0, 0.0, 3074.0));
|
||||||
|
return;
|
||||||
|
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
|
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
|
||||||
|
|
@ -17,9 +23,11 @@ fn main() {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
|
update_external_forces,
|
||||||
fire_thrusters,
|
fire_thrusters,
|
||||||
orbit_camera,
|
orbit_camera,
|
||||||
apply_gravity,
|
apply_gravity.before(update_external_forces),
|
||||||
|
debug_spaceship_orbit,
|
||||||
bevy::window::close_on_esc,
|
bevy::window::close_on_esc,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -34,18 +42,14 @@ struct SpaceshipBundle {
|
||||||
body: RigidBody,
|
body: RigidBody,
|
||||||
collider: Collider,
|
collider: Collider,
|
||||||
restitution: Restitution,
|
restitution: Restitution,
|
||||||
mass: Mass,
|
|
||||||
thrusters: Thrusters,
|
thrusters: Thrusters,
|
||||||
thruster_force: ExternalForce,
|
thruster_force: ExternalForce,
|
||||||
|
forces: ExternalForceSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Spaceship;
|
struct Spaceship;
|
||||||
|
|
||||||
/// Mass in kg.
|
|
||||||
#[derive(Component)]
|
|
||||||
struct Mass(f32);
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Thrusters {
|
struct Thrusters {
|
||||||
/// Strength in some units
|
/// Strength in some units
|
||||||
|
|
@ -53,7 +57,7 @@ struct Thrusters {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct HasGravity {
|
struct GravityAttractor {
|
||||||
mass: f32,
|
mass: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,11 +72,13 @@ struct ThrusterSound;
|
||||||
fn fire_thrusters(
|
fn fire_thrusters(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
keyboard_input: Res<Input<KeyCode>>,
|
keyboard_input: Res<Input<KeyCode>>,
|
||||||
mut query: Query<(&mut ExternalForce, &Thrusters)>,
|
mut query: Query<(&mut ExternalForceSet, &Transform, &Thrusters)>,
|
||||||
sound_query: Query<&AudioSink, With<ThrusterSound>>,
|
sound_query: Query<&AudioSink, With<ThrusterSound>>,
|
||||||
asset_server: Res<AssetServer>,
|
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 keyboard_input.just_pressed(KeyCode::Space) {
|
||||||
if let Ok(sound) = sound_query.get_single() {
|
if let Ok(sound) = sound_query.get_single() {
|
||||||
|
|
@ -89,23 +95,127 @@ fn fire_thrusters(
|
||||||
ThrusterSound,
|
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) {
|
} else if keyboard_input.just_released(KeyCode::Space) {
|
||||||
if let Ok(sound) = sound_query.get_single() {
|
if let Ok(sound) = sound_query.get_single() {
|
||||||
sound.pause();
|
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;
|
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
|
// adapted from https://bevy-cheatbook.github.io/cookbook/pan-orbit-camera.html
|
||||||
fn orbit_camera(
|
fn orbit_camera(
|
||||||
|
|
@ -143,13 +253,14 @@ fn orbit_camera(
|
||||||
|
|
||||||
/// set up a simple 3D scene
|
/// set up a simple 3D scene
|
||||||
fn setup(
|
fn setup(
|
||||||
|
mut windows: Query<&mut Window>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
let mut rapier = RapierConfiguration::default();
|
let mut rapier = RapierConfiguration::default();
|
||||||
// We ain't a normal game, we do our own gravity.
|
// 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.insert_resource(rapier);
|
||||||
|
|
||||||
commands.spawn(PlanetBundle::new(
|
commands.spawn(PlanetBundle::new(
|
||||||
|
|
@ -157,7 +268,7 @@ fn setup(
|
||||||
&mut materials,
|
&mut materials,
|
||||||
Transform::from_xyz(0.0, -100.0, 0.0),
|
Transform::from_xyz(0.0, -100.0, 0.0),
|
||||||
100.0,
|
100.0,
|
||||||
0.0,
|
5000.0,
|
||||||
Color::rgb(0.2, 0.8, 0.5),
|
Color::rgb(0.2, 0.8, 0.5),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
@ -185,6 +296,10 @@ fn setup(
|
||||||
radius: camera_translation.length(),
|
radius: camera_translation.length(),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let mut window = windows.single_mut();
|
||||||
|
// window.cursor.visible = false;
|
||||||
|
window.cursor.grab_mode = CursorGrabMode::Locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpaceshipBundle {
|
impl SpaceshipBundle {
|
||||||
|
|
@ -192,7 +307,7 @@ impl SpaceshipBundle {
|
||||||
let height = 4.0;
|
let height = 4.0;
|
||||||
let width = 0.5;
|
let width = 0.5;
|
||||||
|
|
||||||
Self {
|
SpaceshipBundle {
|
||||||
ship_marker: Spaceship,
|
ship_marker: Spaceship,
|
||||||
model: PbrBundle {
|
model: PbrBundle {
|
||||||
mesh: meshes.add(Mesh::from(shape::Box::new(width, height, width))),
|
mesh: meshes.add(Mesh::from(shape::Box::new(width, height, width))),
|
||||||
|
|
@ -205,10 +320,13 @@ impl SpaceshipBundle {
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
vel: Velocity {
|
vel: Velocity {
|
||||||
linvel: Vec3::ZERO,
|
linvel: Vec3 {
|
||||||
|
x: 100.0,
|
||||||
|
y: 100.0,
|
||||||
|
z: 100.0,
|
||||||
|
},
|
||||||
angvel: Vec3::ZERO,
|
angvel: Vec3::ZERO,
|
||||||
},
|
},
|
||||||
mass: Mass(1000.0),
|
|
||||||
body: RigidBody::Dynamic,
|
body: RigidBody::Dynamic,
|
||||||
collider: Collider::cuboid(width / 2.0, height / 2.0, width / 2.0),
|
collider: Collider::cuboid(width / 2.0, height / 2.0, width / 2.0),
|
||||||
restitution: Restitution::coefficient(0.1),
|
restitution: Restitution::coefficient(0.1),
|
||||||
|
|
@ -217,6 +335,7 @@ impl SpaceshipBundle {
|
||||||
force: Vec3::new(0.0, -0.5, 0.0), // gravity
|
force: Vec3::new(0.0, -0.5, 0.0), // gravity
|
||||||
torque: Vec3::ZERO,
|
torque: Vec3::ZERO,
|
||||||
},
|
},
|
||||||
|
forces: ExternalForceSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +344,7 @@ impl SpaceshipBundle {
|
||||||
struct PlanetBundle {
|
struct PlanetBundle {
|
||||||
mesh: PbrBundle,
|
mesh: PbrBundle,
|
||||||
coll: Collider,
|
coll: Collider,
|
||||||
gravity: HasGravity,
|
gravity: GravityAttractor,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlanetBundle {
|
impl PlanetBundle {
|
||||||
|
|
@ -252,7 +371,7 @@ impl PlanetBundle {
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
coll: Collider::ball(radius),
|
coll: Collider::ball(radius),
|
||||||
gravity: HasGravity { mass },
|
gravity: GravityAttractor { mass },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue