diff --git a/Cargo.toml b/Cargo.toml index 812bcd4adf157..ccb9318dd7683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -376,6 +376,10 @@ path = "examples/input/gamepad_input.rs" name = "gamepad_input_events" path = "examples/input/gamepad_input_events.rs" +[[example]] +name = "gamepad_stick_input" +path = "examples/input/gamepad_stick_input.rs" + [[example]] name = "keyboard_input" path = "examples/input/keyboard_input.rs" diff --git a/assets/textures/crosshair.png b/assets/textures/crosshair.png new file mode 100644 index 0000000000000..e4d6770aeeec5 Binary files /dev/null and b/assets/textures/crosshair.png differ diff --git a/examples/README.md b/examples/README.md index 1ddbd01a583fa..52325db766617 100644 --- a/examples/README.md +++ b/examples/README.md @@ -188,9 +188,10 @@ Example | File | Description Example | File | Description --- | --- | --- -`char_input_events` | [`input/char_input_events.rs`](./input/char_input_events.rs) | Prints out all chars as they are inputted. +`char_input_events` | [`input/char_input_events.rs`](./input/char_input_events.rs) | Prints out all chars as they are input `gamepad_input` | [`input/gamepad_input.rs`](./input/gamepad_input.rs) | Shows handling of gamepad input, connections, and disconnections `gamepad_input_events` | [`input/gamepad_input_events.rs`](./input/gamepad_input_events.rs) | Iterates and prints gamepad input and connection events +`gamepad_stick_input` | [`input/gamepad_stick_input.rs`](./input/gamepad_stick_input.rs) | Shows gamepad stick input graphically `keyboard_input` | [`input/keyboard_input.rs`](./input/keyboard_input.rs) | Demonstrates handling a key press/release `keyboard_input_events` | [`input/keyboard_input_events.rs`](./input/keyboard_input_events.rs) | Prints out all keyboard events `keyboard_modifiers` | [`input/keyboard_modifiers.rs`](./input/keyboard_modifiers.rs) | Demonstrates using key modifiers (ctrl, shift) diff --git a/examples/input/gamepad_stick_input.rs b/examples/input/gamepad_stick_input.rs new file mode 100644 index 0000000000000..8f9e2cfedef5f --- /dev/null +++ b/examples/input/gamepad_stick_input.rs @@ -0,0 +1,135 @@ +use bevy::{input::gamepad::GamepadSettings, prelude::*}; + +const WINDOW_SIZE: f32 = 300.0; +const CROSSHAIR_SIZE: f32 = 16.0; +const FONT: &str = "fonts/FiraMono-Medium.ttf"; +const FONT_SIZE: f32 = 18.0; +const LIVEZONE_COLOR: Color = Color::GRAY; +const DEADZONE_COLOR: Color = Color::rgb(0.4, 0.4, 0.4); + +#[derive(Component)] +struct Crosshair; + +#[derive(Component)] +struct CoordinateText; + +fn main() { + App::new() + .insert_resource(WindowDescriptor { + title: "Gamepad Stick Input".to_owned(), + width: WINDOW_SIZE, + height: WINDOW_SIZE, + ..Default::default() + }) + .insert_resource(ClearColor(DEADZONE_COLOR)) + .add_plugins(DefaultPlugins) + .add_startup_system(setup) + .add_system(update_position) + .run(); +} + +fn update_position( + mut crosshair_query: Query<&mut Transform, With>, + mut text_query: Query<&mut Text, With>, + gamepads: Res, + axes: Res>, +) { + let mut transform = crosshair_query.single_mut(); + let mut text = text_query.single_mut(); + for gamepad in gamepads.iter() { + // We only use input from the left stick. + let x = axes + .get(GamepadAxis(*gamepad, GamepadAxisType::LeftStickX)) + .unwrap(); + let y = axes + .get(GamepadAxis(*gamepad, GamepadAxisType::LeftStickY)) + .unwrap(); + transform.translation.x = x * WINDOW_SIZE / 2.0; + transform.translation.y = y * WINDOW_SIZE / 2.0; + text.sections[0].value = format!("({:6.3}, {:6.3})", x, y); + } +} + +fn setup( + mut commands: Commands, + asset_server: Res, + gamepad_settings: Res, +) { + // Spawn camera + commands.spawn_bundle(OrthographicCameraBundle::new_2d()); + + // Spawn crosshair + let texture = asset_server.load("textures/crosshair.png"); + commands + .spawn_bundle(SpriteBundle { + texture, + sprite: Sprite { + custom_size: Some(Vec2::splat(CROSSHAIR_SIZE)), + ..Default::default() + }, + // Make sure it is in the foreground with a Z value > 0.0 + transform: Transform::from_xyz(0.0, 0.0, 1.0), + ..Default::default() + }) + .insert(Crosshair); + + // Get live/deadzone info + let livezone_upperbound = gamepad_settings.default_axis_settings.positive_high; + let livezone_lowerbound = gamepad_settings.default_axis_settings.negative_high; + let deadzone_upperbound = gamepad_settings.default_axis_settings.positive_low; + let deadzone_lowerbound = gamepad_settings.default_axis_settings.negative_low; + let livezone_midpoint = (livezone_lowerbound + livezone_upperbound) / 2.0; + let deadzone_midpoint = (deadzone_lowerbound + deadzone_upperbound) / 2.0; + let livezone_size = livezone_upperbound - livezone_lowerbound; + let deadzone_size = deadzone_upperbound - deadzone_lowerbound; + let livezone_box_midpoint = livezone_midpoint * WINDOW_SIZE / 2.0; + let deadzone_box_midpoint = deadzone_midpoint * WINDOW_SIZE / 2.0; + let livezone_box_size = livezone_size * WINDOW_SIZE / 2.0; + let deadzone_box_size = deadzone_size * WINDOW_SIZE / 2.0; + // For text placement + let livezone_lower_left_corner = (livezone_box_midpoint - livezone_box_size) / 2.0; + + // Spawn livezone box + commands.spawn_bundle(SpriteBundle { + sprite: Sprite { + custom_size: Some(Vec2::splat(livezone_box_size)), + color: LIVEZONE_COLOR, + ..Default::default() + }, + transform: Transform::from_xyz(livezone_box_midpoint, livezone_box_midpoint, 0.0), + ..Default::default() + }); + // Spawn deadzone box + commands.spawn_bundle(SpriteBundle { + sprite: Sprite { + custom_size: Some(Vec2::splat(deadzone_box_size)), + color: DEADZONE_COLOR, + ..Default::default() + }, + transform: Transform::from_xyz(deadzone_box_midpoint, deadzone_box_midpoint, 0.1), + ..Default::default() + }); + + // Spawn text + let font = asset_server.load(FONT); + let text_style = TextStyle { + font, + font_size: FONT_SIZE, + color: Color::BLACK, + }; + let text_alignment = TextAlignment { + vertical: VerticalAlign::Bottom, + horizontal: HorizontalAlign::Left, + }; + commands + .spawn_bundle(Text2dBundle { + text: Text::with_section("( 0.000, 0.000)", text_style, text_alignment), + transform: Transform::from_xyz( + livezone_lower_left_corner, + livezone_lower_left_corner, + 1.0, + ), + ..Default::default() + }) + .insert(CoordinateText); +}