bevy_silk 0.10.0

Cloth physics implementation in bevy
Documentation
use bevy::{
    input::mouse::{MouseMotion, MouseWheel},
    log,
    prelude::*,
};

pub struct CameraPlugin;

#[derive(Debug, Component)]
pub struct OrbitController;

#[derive(Debug, Component)]
pub struct CameraController;

impl Plugin for CameraPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Startup, setup)
            .add_systems(PostUpdate, (handle_rotation, handle_zoom));
        log::info!("Camera Plugin loaded");
    }
}

pub fn setup(mut commands: Commands) {
    commands
        .spawn((
            Transform::from_rotation(Quat::from_rotation_z(-1.0)),
            Visibility::default(),
            OrbitController,
        ))
        .with_children(|b| {
            b.spawn((
                Camera3d::default(),
                Transform::from_xyz(0.0, 30.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
                CameraController,
            ));
        });
}

pub fn handle_rotation(
    mut cam_controls: Query<&mut Transform, With<OrbitController>>,
    mut motion_evr: MessageReader<MouseMotion>,
    buttons: Res<ButtonInput<MouseButton>>,
    time: Res<Time>,
) {
    let delta_time = time.delta_secs();
    let mut transform = cam_controls.single_mut().unwrap();
    if buttons.pressed(MouseButton::Left) {
        for ev in motion_evr.read() {
            let delta = ev.delta * delta_time * 0.1;
            transform.rotate_y(-delta.x);
            transform.rotate_local_z(delta.y);
        }
    }
}

pub fn handle_zoom(
    mut cam_controls: Query<&mut Transform, With<CameraController>>,
    mut scroll_evr: MessageReader<MouseWheel>,
    time: Res<Time>,
) {
    let delta_time = time.delta_secs();
    let mut transform = cam_controls.single_mut().unwrap();
    let forward = transform.forward();
    for ev in scroll_evr.read() {
        transform.translation += forward * ev.y * delta_time * 10.0;
    }
}