📄 src/camera_controller.rs
use bevy::{
    app::{App, Plugin, Update},
    camera::Camera,
    ecs::{
        query::With,
        schedule::IntoScheduleConfigs,
        system::{If, Res, Single},
    },
    input::{
        ButtonInput,
        gamepad::{Gamepad, GamepadAxis, GamepadButton},
        keyboard::KeyCode,
    },
    math::Vec3,
    transform::components::Transform,
};

use crate::virtual_window::VirtualWindow;

pub struct CameraControllerPlugin;

impl Plugin for CameraControllerPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(
            Update,
            (move_camera_with_keyboard, move_camera_with_controller).chain(),
        );
    }
}

fn move_camera_with_controller(
    camera: Single<(&mut Transform, &VirtualWindow), With<Camera>>,
    gamepad: If<Single<&Gamepad>>,
) {
    let (mut camera, window) = camera.into_inner();
    let mut origin = window.center + window.normal.as_vec3();

    camera.translation = origin;
    camera.look_at(window.center, Vec3::Y);

    origin += camera.local_z().as_vec3()
        * (gamepad
            .get(GamepadButton::LeftTrigger2)
            .and_then(|r| gamepad.get(GamepadButton::RightTrigger2).map(|l| r - l)))
        .unwrap_or_default();
    origin += camera.local_x().as_vec3() * gamepad.get(GamepadAxis::LeftStickX).unwrap_or_default();
    origin += camera.local_y().as_vec3() * gamepad.get(GamepadAxis::LeftStickY).unwrap_or_default();

    camera.translation = origin;
    camera.look_at(window.center, Vec3::Y);
}

fn move_camera_with_keyboard(
    camera: Single<(&mut Transform, &VirtualWindow), With<Camera>>,
    input: Res<ButtonInput<KeyCode>>,
) {
    let (mut camera, window) = camera.into_inner();
    let mut origin = window.center + window.normal.as_vec3();

    camera.translation = origin;
    camera.look_at(window.center, Vec3::Y);

    if input.pressed(KeyCode::KeyS) {
        origin += camera.local_z().as_vec3();
    }
    if input.pressed(KeyCode::KeyW) {
        origin -= camera.local_z().as_vec3();
    }
    if input.pressed(KeyCode::KeyD) {
        origin += camera.local_x().as_vec3();
    }
    if input.pressed(KeyCode::KeyA) {
        origin -= camera.local_x().as_vec3();
    }
    if input.pressed(KeyCode::KeyE) {
        origin += camera.local_y().as_vec3();
    }
    if input.pressed(KeyCode::KeyQ) {
        origin -= camera.local_y().as_vec3();
    }

    camera.translation = origin;
    camera.look_at(window.center, Vec3::Y);
}