Git Product home page Git Product logo

virtual_joystick's Introduction

Bevy Virtual Joystick

VJoystick_Fixed_Preview


GitHub Workflow Status GitHub release (latest by date)

Create and use a Virtual Joystick in a UI for bevy Game Engine.

Versions

Aviable and compatible versions

bevy VirtualJoystick
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 events on Joystick (Press, Drag and Up)
  • Support Axis block (Horizontal, Vertical or Both)

NOTE: To compile android projects you can use cargo-apk or the docker-rust-android project container where you don't have to install or prepare any sdk, for more details see the readme of the mobile projects

Axis

Both (Default) Horizontal Vertical
VJoystick_Fixed_Both VJoystick_Fixed_Horizontal VJoystick_Fixed_Vertical

Joystick Types

Fixed Floating (Default) Dynamic (TODO: Fix movement feel)
VJoystick_Fixed_Both VJoystick_Floating_Both VJoystick_Dynamic_Both

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=inspect

Add to Cargo.toml

[dependencies]
bevy = "0.12"
virtual_joystick = "*" # Add your version

The minimal requirement:

use bevy::prelude::*;
// import crate
use virtual_joystick::*;

// ID for joysticks
#[derive(Default, Reflect, Hash, Clone, PartialEq, Eq)]
enum JoystickControllerID {
    #[default]
    Joystick1,
    Joystick2,
}

#[bevy_main]
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        // Add plugin to application
        .add_plugin(VirtualJoystickPlugin::<JoystickControllerID>::default())
        .run()
}

Create Joystick

#[bevy_main]
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        // Add plugin to application
        .add_plugin(VirtualJoystickPlugin)
        // 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,
        asset_server.load("Knob.png"),
        asset_server.load("Outline.png"),
        None,
        None,
        Some(Color::ORANGE_RED.with_a(0.3)),
        Vec2::new(75., 75.),
        Vec2::new(150., 150.),
        VirtualJoystickNode {
            dead_zone: 0.,
            id: "UniqueJoystick".to_string(),
            axis: VirtualJoystickAxis::Both,
            behaviour: VirtualJoystickType::Floating,
        },
        Style {
            width: Val::Px(150.),
            height: Val::Px(150.),
            position_type: PositionType::Absolute,
            left: Val::Percent(50.),
            bottom: Val::Percent(15.),
            ..default()
        },
    );
}

Use variable generated by Joystick

fn update_joystick(
    mut joystick: EventReader<VirtualJoystickEvent<String>>,
    mut player: Query<(&mut Transform, &Player)>,
    time_step: Res<Time>,
) {
    // Get player
    let (mut player, player_data) = player.single_mut();

    // Iter each joystick event
    for j in joystick.read() {
        let Vec2 { x, y } = j.axis();
        // Verify ID of joystick for movement
        match j.id() {
            JoystickControllerID::Joystick1 => {
                // Move player using joystick axis value
                player.translation.x += x * player_data.0 * time_step.delta_seconds();
                player.translation.y += y * player_data.0 * time_step.delta_seconds();
            }
        }
    }
}

TODOs

  • WIP: Add more better documentation

virtual_joystick's People

Contributors

alexichepura avatar clinuxrulz avatar dror-g avatar johanhelsing avatar ostwilkens avatar patrickchodowski avatar sergioribera avatar vrixyz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

virtual_joystick's Issues

Order Render

Describe the bug
The order render of knob and background is bad

To Reproduce
Steps to reproduce the behavior:

  1. Clone the main branch
  2. Change with diferent colors to knob and background on example
  3. Run example with cargo run --example <example_name> -F inspect

Expected behavior
knob above the background

Desktop (please complete the following information):

  • OS: Any
  • Browser Any
  • Version Any

Smartphone (please complete the following information):

  • Device: Any
  • OS: Any
  • Browser Any
  • Version Any

Screenshots
out

Option to limit the knob movement to circular area

Is your feature request related to a problem? Please describe.

Can be more visually pleasing when the knob is constrained in the outline. Also it prevents the player from moving faster in the diagonal direction vs the horizontal or vertical directions by default.

Describe the solution you'd like
Just an extra component to make the joystick knob constrained to a circular area.

Describe alternatives you've considered
None

Additional context
N/A

Documentation error

Just a documentation error:

Inside VirtualJoystickEvent<S>:

    /// Delta value ranging from 0 to 1 in each vector (x and y)
    pub fn axis(&self) -> Vec2 {
        self.delta
    }

I thought from the documentation for x-axis 0 was all the way to the left, and 1 is all the way to right right.
But for the x-axis -1 is left and +1 is right. Similar for y-axis.

Maybe it should say:
/// Delta value ranging from -1 to 1 in each vector (x and y)

Dynamic joystick adjustment

Is your feature request related to a problem? Please describe.
Fix feel of dynamic joystick.

Describe the solution you'd like
Dynamic joystick should work and visually appear just like Floating joystick. However the joystick will move as the knob moves outside its interactive boundary. I.E. the joystick moves when needed to keep knob in boundary instead of moving knob to keep knob in boundary. I believe that is all we need to do to fix the feel of dynamic joystick.

The movement of the boundary would have to be in the same vector direction at the knob when the knob goes out of boundary too.

Describe alternatives you've considered
None

Additional context
The dynamic joystick in this project is call following joystick in this other project:
https://github.com/MarcoFazioRandom/Virtual-Joystick-Godot
Quote: "Following: When the finger moves outside the joystick area, the joystick will follow it.".

Mobile browser touch events

When targeting Web Assembly then running it on a mobile browser, it seems this plugin is looking for mouse events instead of touch events.

Maybe for desktop PC it should look for both touch events and mouse events. Plenty of laptops have touch screen these days.

std::env::consts::OS contains an empty string for the Web Assembly target.

Externalize behaviors

This is a feature that I would like to implement, the idea would be to achieve something like this

fn create_scene(mut cmd: Commands) {
    // Spawn Virtual Joystick
    cmd.spawn(
        VirtualJoystickBundle::new(VirtualJoystickNode {
            // ....
            // Feature
            action: ClickColor(Color::WHITE.with_a(0.5)),
        })
    )
    .insert(BackgroundColor(Color::ORANGE_RED.with_a(0.3)))
    .insert(VirtualJoystickInteractionArea);
}

The idea is actually that there are actions already defined by default by the plugin but the user can also create their own actions like this

pub struct ClickColor(pub Color);

impl VirtualJoystickAction for ClickColor {
  pub fn on_click(&self, world: &mut World, entity: Entity) {
    let tint = world.get_mut<TintColor>().unwrap();
    *tint = TintColor(self.0);
  }
}

The trait should be something like this

pub trait VirtualJoystickAction {
  fn on_click(&self, _world: &mut World, _entity: Entity) { }
  fn on_drag(&self, _world: &mut World, _entity: Entity) { }
  fn on_end_drag(&self, _world: &mut World, _entity: Entity) { }
  fn on_up(&self, _world: &mut World, _entity: Entity) { }
}

Make joystick invisible when not is use

Is your feature request related to a problem? Please describe.
The joystick takes up space on the screen.

Describe the solution you'd like
If the user is not holding down the mouse button, or is not touching the screen, the joystick should not be visible. The joystick area will appear wherever the user clicks / touches.

Describe alternatives you've considered
Create a custom system that checks for mouse state and modifies the joystick entity. But I do not know how to do this.

Additional context
N/A

Add Licensing?

Hello! This is a really nice library and I'm looking forward to trying it out!

Though you've mentioned the license in your Cargo.toml being MIT OR Apache-2.0, I would highly recommend adding the respective license file(s) in the repository.

This will make it clear about the library licensing and will also show up in the license sections on GitHub. Making it easier to find.

Here are the license files from the Bevy repository for reference: MIT and APACHE. Hope this helps.

Good luck with this ๐Ÿš€

bevy_sprite instead of bevy_ui, rework API?

Seems like a neat little project. It has a lot of stuff I want, but also quite a few things I'd like to change/add. I'm wondering whether you'd want PRs to fix this, or if it's better that I create my own fork.

Is your feature request related to a problem? Please describe.

  • bevy_sprite instead of bevy_ui. Bevy ui is still not ready for use in my opinion, I'd rather have something that works with sprites or some modular mechanism for rendering.
  • Resources or entities instead of events. Event's are kind of clunky to work with, it would be more convenient for me to be able to do something like joystick: Res<VirtualJoystick> and translation.x += joystick.x() * speed. More in line with how other bevy input APIs work.
  • Optinal integration with leafwing input manager through feature flag.

Additional context
I need this functionality pretty soon.

Sorry, if this seems like critique, I guess it technically is, but I'm also really grateful that you took the time to contribute this to the community. Will probably save me some time โค๏ธ

Interaction area controls Joystick sensitivity - problem on bigger displays / area

The Interaction Area rectangle defines where a joystick will appear / move to on touch in Floating mode,
But it also controls how far the joystick can be dragged = how sensitive it is.

The bigger the area - the more the joystick can be dragged - smaller output numbers per cm.

This is a problem on bigger screens like tablets or phones with high resolution.
If you want the user to be able to touch anywhere on screen he needs to drag the joystick all the way from side to side to get full motion range.

Of course the output vec could be multiplied, but the ui is also affected, and if screen size is unknown and area rect is scaled using Percent - the output multiplier might not be suitable.

To Reproduce
Set joystick area to larger figures:
width: Val::Px(450.) or width: Val::Percent(100.)
Use joystick app on larger screen, longer drag required to max range.

Compare with more standard settings:
width: Val::Px(150.) or width: Val::Percent(30.)
shorter drag required to max range.

Expected behavior
Interaction Area should control where the joystick will appear on touch, not sensitivity.
Joystick range of motion should be fixed, controlled by another area parameter perhaps?

Desktop

  • OS: Linux, native and wasm (using mouse)
  • Browser Chrome and Firefox
  • Version 2.1.0

Smartphone

  • Device: Samsung A71
  • OS: Android 12
  • Browser Chrome
  • Version 2.1.0

Additional context
PC resoulution 1280x720 , 800x600
Samsung A71 1920x1080

Thank you!!!!

Don't depend on bevy default-features

Describe the bug

Depending on bevy means that it's not possible for users of this crate to not pull in bevy_gltf etc. for use in 2D project. This creates unnecessary large builds.

Expected behavior

Have default-features = false for bevy, specify just the needed features.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.