This commit is contained in:
nora 2023-09-16 17:21:50 +02:00
parent c97d11b072
commit 07f17e5e02
3 changed files with 174 additions and 54 deletions

BIN
assets/thrusters_loop.ogg Normal file

Binary file not shown.

View file

@ -46,6 +46,7 @@
''-I${pkgs.glib.out}/lib/glib-2.0/include/'' ''-I${pkgs.glib.out}/lib/glib-2.0/include/''
]; ];
packages = (with pkgs; [ packages = (with pkgs; [
ffmpeg
]); ]);
}; };
}); });

View file

@ -1,6 +1,11 @@
//! A simple 3D scene with light shining over a cube sitting on a plane. //! A simple 3D scene with light shining over a cube sitting on a plane.
use bevy::prelude::*; use bevy::{
audio::PlaybackMode,
input::mouse::{MouseMotion, MouseWheel},
prelude::*,
window::PrimaryWindow,
};
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
fn main() { fn main() {
@ -10,10 +15,12 @@ fn main() {
.add_plugins(RapierDebugRenderPlugin::default()) .add_plugins(RapierDebugRenderPlugin::default())
.add_systems(Startup, setup) .add_systems(Startup, setup)
.add_systems( .add_systems(
FixedUpdate, Update,
( (
apply_velocity, fire_thrusters,
fire_thrusters.after(apply_velocity), orbit_camera,
apply_gravity,
bevy::window::close_on_esc,
), ),
) )
.run(); .run();
@ -24,42 +31,113 @@ struct SpaceshipBundle {
ship_marker: Spaceship, ship_marker: Spaceship,
model: PbrBundle, model: PbrBundle,
vel: Velocity, vel: Velocity,
gravity: Gravity,
body: RigidBody, body: RigidBody,
collider: Collider, collider: Collider,
restitution: Restitution, restitution: Restitution,
mass: Mass,
thrusters: Thrusters,
thruster_force: ExternalForce,
} }
#[derive(Component, Deref, DerefMut)]
struct Velocity(Vec3);
#[derive(Component)] #[derive(Component)]
struct Spaceship; struct Spaceship;
/// Mass in kg.
#[derive(Component)] #[derive(Component)]
struct Gravity; struct Mass(f32);
#[derive(Component)] #[derive(Component)]
struct Ground; struct Thrusters {
/// Strength in some units
strength: f32,
}
#[derive(Component)]
struct HasGravity {
mass: f32,
}
#[derive(Component)]
struct OrbitCamera {
radius: f32,
}
#[derive(Component)]
struct ThrusterSound;
fn fire_thrusters( fn fire_thrusters(
mut commands: Commands,
keyboard_input: Res<Input<KeyCode>>, keyboard_input: Res<Input<KeyCode>>,
mut query: Query<&mut Velocity, With<Spaceship>>, mut query: Query<(&mut ExternalForce, &Thrusters)>,
time_step: Res<FixedTime>, sound_query: Query<&AudioSink, With<ThrusterSound>>,
asset_server: Res<AssetServer>,
) { ) {
let mut transform = query.single_mut(); let (mut force, thrusters) = query.single_mut();
if keyboard_input.pressed(KeyCode::Space) { if keyboard_input.just_pressed(KeyCode::Space) {
transform.y += 10.0 * time_step.period.as_secs_f32(); if let Ok(sound) = sound_query.get_single() {
sound.play();
} else {
commands.spawn((
AudioBundle {
source: asset_server.load("thrusters_loop.ogg"),
settings: PlaybackSettings {
mode: PlaybackMode::Loop,
..default()
},
},
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();
}
force.force = Vec3::ZERO;
} }
} }
// TODO: DELETE fn apply_gravity(query: Query<&mut ExternalForce, With<Spaceship>>) {}
fn apply_velocity(mut query: Query<(&mut Transform, &Velocity)>, time_step: Res<FixedTime>) {
for (mut trans, vel) in &mut query { // adapted from https://bevy-cheatbook.github.io/cookbook/pan-orbit-camera.html
trans.translation.x += vel.x * time_step.period.as_secs_f32(); fn orbit_camera(
trans.translation.y += vel.y * time_step.period.as_secs_f32(); mut ev_motion: EventReader<MouseMotion>,
trans.translation.z += vel.z * time_step.period.as_secs_f32(); mut ev_scroll: EventReader<MouseWheel>,
mut query: Query<(&mut OrbitCamera, &mut Transform), Without<Spaceship>>,
spaceship_query: Query<&Transform, With<Spaceship>>,
window_query: Query<&Window, With<PrimaryWindow>>,
) {
let window = window_query.single();
let rotation_move: Vec2 = ev_motion.iter().map(|ev| ev.delta).sum();
let scroll: f32 = ev_scroll.iter().map(|ev| ev.y).sum();
for (mut orbit, mut transform) in &mut query {
if rotation_move.length_squared() > 0.0 {
let window = Vec2::new(window.width(), window.height());
let delta_x = rotation_move.x / window.x * std::f32::consts::PI * 2.0;
let delta_y = rotation_move.y / window.y * std::f32::consts::PI;
let yaw = Quat::from_rotation_y(-delta_x);
let pitch = Quat::from_rotation_x(-delta_y);
transform.rotation *= yaw;
transform.rotation *= pitch;
}
if scroll.abs() > 0.0 {
orbit.radius -= scroll * orbit.radius * 0.2;
// dont allow zoom to reach zero or you get stuck
orbit.radius = f32::max(orbit.radius, 0.05);
}
let rot_matrix = Mat3::from_quat(transform.rotation);
transform.translation = spaceship_query.single().translation
+ rot_matrix.mul_vec3(Vec3::new(0.0, 0.0, orbit.radius));
} }
} }
@ -69,20 +147,18 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
// plane let mut rapier = RapierConfiguration::default();
commands.spawn(( // We ain't a normal game, we do our own gravity.
PbrBundle { rapier.gravity = Vec3::new(0.0, -0.5, 0.0);
mesh: meshes.add(shape::Plane::from_size(5.0).into()), commands.insert_resource(rapier);
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
transform: Transform::from_scale(Vec3 { commands.spawn(PlanetBundle::new(
x: 5.0, &mut meshes,
y: 1.0, &mut materials,
z: 5.0, Transform::from_xyz(0.0, -100.0, 0.0),
}), 100.0,
..default() 0.0,
}, Color::rgb(0.2, 0.8, 0.5),
Ground,
Collider::cuboid(5.0, 0.1, 5.0),
)); ));
commands.spawn(SpaceshipBundle::new(&mut meshes, &mut materials)); commands.spawn(SpaceshipBundle::new(&mut meshes, &mut materials));
@ -97,43 +173,86 @@ fn setup(
..default() ..default()
}); });
// camera // camera
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), let camera_translation = Vec3::new(-2.0, 2.5, 5.0);
..default() commands.spawn((
}); Camera3dBundle {
transform: Transform::from_translation(camera_translation)
.looking_at(Vec3::ZERO, Vec3::Y),
..default()
},
OrbitCamera {
radius: camera_translation.length(),
},
));
} }
impl SpaceshipBundle { impl SpaceshipBundle {
fn new(meshes: &mut Assets<Mesh>, materials: &mut Assets<StandardMaterial>) -> Self { fn new(meshes: &mut Assets<Mesh>, materials: &mut Assets<StandardMaterial>) -> Self {
let height = 4.0;
let width = 0.5;
Self { Self {
ship_marker: Spaceship, ship_marker: Spaceship,
model: PbrBundle { model: PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), mesh: meshes.add(Mesh::from(shape::Box::new(width, height, width))),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 0.5, 0.0).with_scale(Vec3 { transform: Transform::from_xyz(0.0, 3.0, 0.0).with_scale(Vec3 {
x: 1.0, x: 1.0,
y: 1.0, y: 1.0,
z: 1.0, z: 1.0,
}), }),
..default() ..default()
}, },
vel: Velocity(Vec3::default()), vel: Velocity {
gravity: Gravity, linvel: Vec3::ZERO,
angvel: Vec3::ZERO,
},
mass: Mass(1000.0),
body: RigidBody::Dynamic, body: RigidBody::Dynamic,
collider: Collider::ball(0.5), collider: Collider::cuboid(width / 2.0, height / 2.0, width / 2.0),
restitution: Restitution::coefficient(0.1), restitution: Restitution::coefficient(0.1),
thrusters: Thrusters { strength: 1.0 },
thruster_force: ExternalForce {
force: Vec3::new(0.0, -0.5, 0.0), // gravity
torque: Vec3::ZERO,
},
} }
} }
} }
fn collides(a_pos: Vec3, a_size: Vec3, b_pos: Vec3, b_size: Vec3) -> bool { #[derive(Bundle)]
let a_min = a_pos - a_size / 2.0; struct PlanetBundle {
let a_max = a_pos + a_size * 2.0; mesh: PbrBundle,
let b_min = b_pos - b_size / 2.0; coll: Collider,
let b_max = b_pos + b_size / 2.0; gravity: HasGravity,
}
let axis_collides =
|axis: fn(Vec3) -> f32| axis(a_min) < axis(b_max) && axis(a_max) > axis(b_min); impl PlanetBundle {
fn new(
axis_collides(|v| v.x) && axis_collides(|v| v.y) && axis_collides(|v| v.z) meshes: &mut Assets<Mesh>,
materials: &mut Assets<StandardMaterial>,
position: Transform,
radius: f32,
mass: f32,
color: Color,
) -> Self {
PlanetBundle {
mesh: PbrBundle {
mesh: meshes.add(
shape::UVSphere {
radius,
sectors: 100,
stacks: 100,
}
.into(),
),
material: materials.add(color.into()),
transform: position,
..default()
},
coll: Collider::ball(radius),
gravity: HasGravity { mass },
}
}
} }