bones_bevy_renderer/
input.rs

1use super::*;
2use bevy::{
3    input::{
4        keyboard::KeyboardInput,
5        mouse::{MouseButtonInput, MouseMotion, MouseWheel},
6    },
7    window::PrimaryWindow,
8};
9use bones::{MouseScreenPosition, MouseWorldPosition};
10use bones_framework::input::gilrs::process_gamepad_events;
11
12/// Bevy system that takes the bones input resources as input and inserts them
13/// into the [`BonesGame`].
14pub fn insert_bones_input(
15    In((mouse_inputs, keyboard_inputs, gamepad_inputs)): In<(
16        bones::MouseInputs,
17        bones::KeyboardInputs,
18        bones::GamepadInputs,
19    )>,
20    mut game: ResMut<BonesGame>,
21) {
22    // Add the game inputs
23    game.insert_shared_resource(mouse_inputs);
24    game.insert_shared_resource(keyboard_inputs);
25    game.insert_shared_resource(gamepad_inputs);
26}
27
28/// Bevy system that gets the input events and returns the bones versions.
29pub fn get_bones_input(
30    mut mouse_button_input_events: EventReader<MouseButtonInput>,
31    mut mouse_motion_events: EventReader<MouseMotion>,
32    mut mouse_wheel_events: EventReader<MouseWheel>,
33    mut keyboard_events: EventReader<KeyboardInput>,
34) -> (
35    bones::MouseInputs,
36    bones::KeyboardInputs,
37    bones::GamepadInputs,
38) {
39    // TODO: investigate possible ways to avoid allocating vectors every frame for event lists.
40    (
41        bones::MouseInputs {
42            movement: mouse_motion_events
43                .iter()
44                .last()
45                .map(|x| x.delta)
46                .unwrap_or_default(),
47            wheel_events: mouse_wheel_events
48                .iter()
49                .map(|event| bones::MouseScrollEvent {
50                    unit: event.unit.into_bones(),
51                    movement: Vec2::new(event.x, event.y),
52                })
53                .collect(),
54            button_events: mouse_button_input_events
55                .iter()
56                .map(|event| bones::MouseButtonEvent {
57                    button: event.button.into_bones(),
58                    state: event.state.into_bones(),
59                })
60                .collect(),
61        },
62        bones::KeyboardInputs {
63            key_events: keyboard_events
64                .iter()
65                .map(|event| bones::KeyboardEvent {
66                    scan_code: event.scan_code,
67                    key_code: event.key_code.map(|x| x.into_bones()).into(),
68                    button_state: event.state.into_bones(),
69                })
70                .collect(),
71        },
72        process_gamepad_events(),
73    )
74}
75
76/// Bevy system that takes the mouse positions for the world and screen as input
77/// and inserts them into the [`BonesGame`].
78pub fn insert_mouse_position(
79    In((screen_pos, world_pos)): In<(Option<Vec2>, Option<Vec2>)>,
80    mut game: ResMut<BonesGame>,
81) {
82    game.insert_shared_resource(MouseScreenPosition(screen_pos));
83    game.insert_shared_resource(MouseWorldPosition(world_pos));
84}
85
86// Source: https://bevy-cheatbook.github.io/cookbook/cursor2world.html
87/// Bevy system that returns the mouse positions for the screen and world.
88pub fn get_mouse_position(
89    mut q_primary_windows: Query<&Window, With<PrimaryWindow>>,
90    q_camera: Query<(&Camera, &GlobalTransform)>,
91) -> (Option<Vec2>, Option<Vec2>) {
92    match q_primary_windows
93        .get_single_mut()
94        .ok()
95        .and_then(Window::cursor_position)
96    {
97        None => (None, None),
98        screen_pos @ Some(sp) => match q_camera.get_single() {
99            Err(_) => (screen_pos, None),
100            Ok((camera, camera_transform)) => {
101                let world_pos = camera.viewport_to_world_2d(camera_transform, sp);
102                (screen_pos, world_pos)
103            }
104        },
105    }
106}