some_bevy_tools 0.2.4

A collection of tools which can be used in the Bevy Engine.
Documentation
//! A third party controller system for a third person camera.
//!
//! This system allows the player to control a camera in a third person perspective.
//! The camera can be rotated around the player and moved in the x and z direction.
//! It will produce events for mostly used user inputs.
use std::f32::consts::PI;

use bevy::prelude::*;

use crate::input::SliderMappingType;
use crate::{input, third_party_camera};

#[derive(Component)]
pub struct ThirdPartyController {
    pub min_distance: f32,
    pub max_distance: f32,
}

#[derive(Clone, Eq, PartialEq, Hash)]
pub enum CharacterControllerEvent {
    Turn,
    IncreaseCameraDistance,
    DecreaseCameraDistance,
    MoveForward,
    MoveBackward,
    MoveLeft,
    MoveRight,
}

pub fn default_character_controller_event_mapping() -> input::InputMapping<CharacterControllerEvent>
{
    input::InputMapping::from((
        [
            (
                input::UserButtonInput::MouseScrollDown,
                CharacterControllerEvent::IncreaseCameraDistance,
            ),
            (
                input::UserButtonInput::MouseScrollUp,
                CharacterControllerEvent::DecreaseCameraDistance,
            ),
            (
                input::UserButtonInput::KeyPressed(KeyCode::KeyW),
                CharacterControllerEvent::MoveForward,
            ),
            (
                input::UserButtonInput::KeyPressed(KeyCode::KeyS),
                CharacterControllerEvent::MoveBackward,
            ),
            (
                input::UserButtonInput::KeyPressed(KeyCode::KeyA),
                CharacterControllerEvent::MoveLeft,
            ),
            (
                input::UserButtonInput::KeyPressed(KeyCode::KeyD),
                CharacterControllerEvent::MoveRight,
            ),
        ],
        [(
            SliderMappingType::MouseMove(10.0),
            CharacterControllerEvent::Turn,
            0.005,
            -0.005,
        )],
    ))
}

pub fn third_party_camera_controller_system(
    mut action_events: EventReader<input::ActionEvent<CharacterControllerEvent>>,
    mut slider_events: EventReader<input::DirectionSliderEvent<CharacterControllerEvent>>,
    mut third_party_query: Query<(
        &ThirdPartyController,
        &mut third_party_camera::ThirdPartyCamera,
    )>,
) {
    for ev in action_events.read() {
        match ev.action {
            CharacterControllerEvent::IncreaseCameraDistance => {
                let offset = 1.0;
                for (controller, mut camera) in third_party_query.iter_mut() {
                    camera.distance = (camera.distance - offset)
                        .clamp(controller.min_distance, controller.max_distance);
                }
            }
            CharacterControllerEvent::DecreaseCameraDistance => {
                let offset = -1.0;
                for (controller, mut camera) in third_party_query.iter_mut() {
                    camera.distance = (camera.distance - offset)
                        .clamp(controller.min_distance, controller.max_distance);
                }
            }
            _ => (),
        }
    }

    for ev in slider_events.read() {
        for (_controller, mut camera) in third_party_query.iter_mut() {
            camera.rotate_y -= ev.x;
            camera.rotate_x = (camera.rotate_x - ev.y).clamp(-PI / 2.0 + 0.01, PI / 2.0 - 0.01);
        }
    }
}

pub fn move_controller_plane(
    camera_query: Query<&third_party_camera::ThirdPartyCamera, With<ThirdPartyController>>,
    mut target_query: Query<&mut Transform, Without<ThirdPartyController>>,
    mut action_events: EventReader<input::ActionEvent<CharacterControllerEvent>>,
    time: Res<Time>,
) {
    for ev in action_events.read() {
        match ev.action {
            CharacterControllerEvent::MoveForward => {
                for camera in camera_query.iter() {
                    if let Ok(mut target_transform) = target_query.get_mut(camera.target) {
                        let rotation_y = camera.rotate_y;
                        target_transform.translation.x -=
                            rotation_y.sin() * 10.0 * time.delta_seconds();
                        target_transform.translation.z -=
                            rotation_y.cos() * 10.0 * time.delta_seconds();

                        target_transform.rotation = Quat::from_rotation_y(rotation_y);
                    }
                }
            }
            CharacterControllerEvent::MoveBackward => {
                for camera in camera_query.iter() {
                    if let Ok(mut target_transform) = target_query.get_mut(camera.target) {
                        let rotation_y = camera.rotate_y;
                        target_transform.translation.x +=
                            rotation_y.sin() * 10.0 * time.delta_seconds();
                        target_transform.translation.z +=
                            rotation_y.cos() * 10.0 * time.delta_seconds();

                        target_transform.rotation = Quat::from_rotation_y(rotation_y);
                    }
                }
            }
            CharacterControllerEvent::MoveLeft => {
                for camera in camera_query.iter() {
                    if let Ok(mut target_transform) = target_query.get_mut(camera.target) {
                        let rotation_y = camera.rotate_y;
                        target_transform.translation.x -=
                            rotation_y.cos() * 10.0 * time.delta_seconds();
                        target_transform.translation.z +=
                            rotation_y.sin() * 10.0 * time.delta_seconds();

                        target_transform.rotation = Quat::from_rotation_y(rotation_y);
                    }
                }
            }
            CharacterControllerEvent::MoveRight => {
                for camera in camera_query.iter() {
                    if let Ok(mut target_transform) = target_query.get_mut(camera.target) {
                        let rotation_y = camera.rotate_y;
                        target_transform.translation.x +=
                            rotation_y.cos() * 10.0 * time.delta_seconds();
                        target_transform.translation.z -=
                            rotation_y.sin() * 10.0 * time.delta_seconds();

                        target_transform.rotation = Quat::from_rotation_y(rotation_y);
                    }
                }
            }
            _ => (),
        }
    }
}

pub struct ThirdPartyControllerPlugin;
impl Plugin for ThirdPartyControllerPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins((
            third_party_camera::ThirdPartyCameraPlugin,
            input::InputMappingPlugin::<CharacterControllerEvent>::default(),
        ))
        .insert_resource(default_character_controller_event_mapping())
        .add_systems(Update, third_party_camera_controller_system);
    }
}