OrbitalSimulator/src/bin/orbiter.rs
2025-06-20 00:24:03 -04:00

103 lines
3.1 KiB
Rust

use bevy::prelude::*;
use bevy::input::mouse::{MouseMotion, MouseWheel};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, (camera_orbit_controls,))
.run();
}
#[derive(Component)]
struct CameraController {
pub radius: f32,
pub theta: f32, // azimuthal angle
pub phi: f32, // polar angle
pub last_mouse_pos: Option<Vec2>,
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// Camera with controller
let radius = 30.0;
let theta = 0.0;
let phi = std::f32::consts::FRAC_PI_4;
let cam_pos = spherical_to_cartesian(radius, theta, phi);
commands.spawn((
Camera3dBundle {
transform: Transform::from_translation(cam_pos).looking_at(Vec3::ZERO, Vec3::Y),
..default()
},
CameraController {
radius,
theta,
phi,
last_mouse_pos: None,
},
));
// Light
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
// Add a sphere at the origin using the new Sphere primitive
let mesh = meshes.add(Mesh::from(Sphere { radius: 1.0, ..default() }));
let material = materials.add(StandardMaterial {
base_color: Color::BLUE,
..default()
});
commands.spawn(PbrBundle {
mesh,
material,
..default()
});
}
fn spherical_to_cartesian(radius: f32, theta: f32, phi: f32) -> Vec3 {
let x = radius * phi.sin() * theta.cos();
let y = radius * phi.cos();
let z = radius * phi.sin() * theta.sin();
Vec3::new(x, y, z)
}
fn camera_orbit_controls(
mut query: Query<(&mut Transform, &mut CameraController)>,
mut mouse_motion_events: EventReader<MouseMotion>,
mut mouse_wheel_events: EventReader<MouseWheel>,
mouse_button_input: Res<ButtonInput<MouseButton>>,
windows: Query<&Window>,
) {
let window = if let Some(window) = windows.iter().next() { window } else { return; };
let mut delta = Vec2::ZERO;
for event in mouse_motion_events.read() {
delta += event.delta;
}
let mut scroll = 0.0;
for event in mouse_wheel_events.read() {
scroll += event.y;
}
for (mut transform, mut controller) in query.iter_mut() {
// Orbit (right mouse button)
if mouse_button_input.pressed(MouseButton::Right) {
let sensitivity = 0.01;
controller.theta -= delta.x * sensitivity;
controller.phi = (controller.phi - delta.y * sensitivity).clamp(0.05, std::f32::consts::PI - 0.05);
}
// Zoom
if scroll.abs() > 0.0 {
controller.radius = (controller.radius - scroll).clamp(3.0, 200.0);
}
// Update camera position
let pos = spherical_to_cartesian(controller.radius, controller.theta, controller.phi);
*transform = Transform::from_translation(pos).looking_at(Vec3::ZERO, Vec3::Y);
}
}