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"
|
||||
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]]
|
||||
|
|
|
|||
|
|
@ -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
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::{
|
||||
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 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue