Create and use a Virtual Joystick in a UI for bevy Game Engine.
Versions
Aviable and compatible versions
| bevy | VirtualJoystick |
|---|---|
| 0.19 | 2.8.0 |
| 0.18 | 2.7.2 |
| 0.17 | 2.6.0 |
| 0.16 | 2.5.3 |
| 0.15 | 2.4.0 |
| 0.14 | 2.3.0 |
| 0.13 | 2.2.0 |
| 0.12 | 2.1.0 |
| 0.11 | 2.0.1 |
| 0.10.1 | 1.1.2 |
Features
- Support Mouse and Touch
- Easy usage
- Multiple Joysticks on screen
- Multiple types of joystick behaviour
- Track Messages on Joystick (Press, Drag and Up)
- Support Axis block (Horizontal, Vertical or Both)
NOTE: To compile android projects you can use cargo-ndk. See the Android Section of the bevy example
README.mdfor details.
Axis
| Both (Default) | Horizontal | Vertical |
|---|---|---|
![]() |
![]() |
![]() |
Joystick Types
| Fixed | Floating (Default) | Dynamic (TODO: Fix movement feel) |
|---|---|---|
![]() |
![]() |
![]() |
Examples
Features
- inspect: for world inspect with egui inspector
serde(default): for serialization support for all types (usable for save and load settings)
virtual_joystick = { version = "*", default-features = false, features = [ "inspect", "serde" ] }
Usage
Check out the examples for details.
# to run example
cargo run --example simple -F=inspectAdd to Cargo.toml
[dependencies] bevy = "*" virtual_joystick = "*" # Add your version
The minimal requirement:
use bevy::prelude::*; // import crate use virtual_joystick::*; /// ID for joysticks #[derive(Default, Debug, Reflect, Hash, Clone, PartialEq, Eq)] enum JoystickControllerID { #[default] Joystick1, Joystick2, } #[bevy_main] fn main() { App::new() .add_plugins(DefaultPlugins) // Add plugin to application .add_plugins(VirtualJoystickPlugin::<JoystickControllerID>::default()) .run() }
Create Joystick
#[bevy_main] fn main() { App::new() .add_plugins(DefaultPlugins) // Add plugin to application .add_plugins(VirtualJoystickPlugin::<String>::default()) // Create system .add_startup_system(create_scene) // update System .add_system(update_player) .run() } fn create_scene(mut cmd: Commands, asset_server: Res<AssetServer>) { cmd.spawn(Camera2dBundle::default()); cmd.spawn_empty().insert(Player(30.)); // Spawn Virtual Joystick at horizontal center create_joystick( &mut cmd, "UniqueJoystick".to_string(), asset_server.load("Knob.png"), asset_server.load("Outline.png"), None, None, Some(Color::srgba(1.0, 0.27, 0.0, 0.3)), Vec2::new(75., 75.), Vec2::new(150., 150.), Node { width: Val::Percent(100.), height: Val::Percent(100.), position_type: PositionType::Absolute, left: Val::Percent(0.), bottom: Val::Percent(0.), ..default() }, JoystickFloating, NoAction, ); }
Use variable generated by Joystick
fn update_joystick( mut reader: MessageReader<VirtualJoystickMessage<JoystickControllerID>>, player: Single<(&mut Transform, &Player)>, time_step: Res<Time>, ) { // Get player let (mut player, player_data) = player.into_inner(); // Iter each `VirtualJoystickMessage` for joystick in reader.read() { let Vec2 { x, y } = joystick.axis(); // Verify ID of joystick for movement match joystick.id() { JoystickControllerID::Joystick1 => { // Move player using joystick axis value player.translation.x += x * player_data.0 * time_step.delta_secs(); player.translation.y += y * player_data.0 * time_step.delta_secs(); } } } }
TODOs
- WIP: Add more better documentation





