Bevy virtual Joystick for mobile games (Works with mouse on desktop)

Overview

Bevy Virtual Joystick

VJoystick_Fixed_Preview

Crates.io

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

Versions

Aviable and compatible versions

bevy VirtualJoystick
0.10.1 1.0.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)

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

Usage

Check out the examples for details.

Add to Cargo.toml

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

To solve sizing issue

[patch.crates-io]
android-activity = { git = "https://github.com/MarijnS95/android-activity/", branch = "na-resize"}

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
    cmd.spawn(
        // Define variable for Joystick
        VirtualJoystickBundle::new(VirtualJoystickNode {
            border_image: asset_server.load("Outline.png"),
            knob_image: asset_server.load("Knob.png"),
            knob_size: Vec2::new(80., 80.),
            dead_zone: 0.,
            id: JoystickControllerID::Joystick1,
            axis: VirtualJoystickAxis::Horizontal,
            behaviour: VirtualJoystickType::Fixed,
        })
        .set_color(TintColor(Color::WHITE))
        .set_style(Style {
            size: Size::all(Val::Px(150.)),
            position_type: PositionType::Absolute,
            position: UiRect {
                left: Val::Percent(50.),
                bottom: Val::Percent(15.),
                ..default()
            },
            ..default()
        }),
    )
    // When you add this component you mark this area as interactable for Joystick
    .insert(VirtualJoystickInteractionArea);
}

Use variable generated by Joystick

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

    // Iter each joystick event
    for j in joystick.iter() {
        // get axis value 0-1 in x & y
        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.period.as_secs_f32();
                player.translation.y += y * player_data.0 * time_step.period.as_secs_f32();
            }
        }
    }
}

Types

enum VirtualJoystickAxis {
    Both, // Default
    Horizontal,
    Vertical,
}

enum VirtualJoystickType {
    /// Static position
    Fixed,
    /// Spawn at point click
    /// Default
    Floating,
    /// Follow point on drag
    Dynamic,
}

// Component
struct VirtualJoystickNode {
    /// Identifier of joystick
    /// Note: any type that implements Hash + Clone + Default + Reflect
    pub id: S,
    /// Image for background or border image on joystick
    pub border_image: Handle<Image>,
    /// Image for handler knob on joystick
    pub knob_image: Handle<Image>,
    /// Size for knob on joystick
    pub knob_size: Vec2,
    /// Zone to ignore movement
    pub dead_zone: f32,
    /// Define Axis for this joystick
    pub axis: VirtualJoystickAxis,
    /// Define the behaviour of joystick
    pub behaviour: VirtualJoystickType,
}

// Event Type
pub enum VirtualJoystickEventType {
    Press,
    Drag,
    Up
}

// EventReader
struct VirtualJoystickEvent {
    /// Get ID of joystick throw event
    pub fn id(&self) -> S;

    /// Return the Type of Joystick Event
    pub fn get_type(&self) -> VirtualJoystickEventType;

    /// Raw position of point (Mouse or Touch)
    pub fn value(&self) -> Vec2;

    /// Axis of Joystick see [crate::VirtualJoystickAxis]
    pub fn direction(&self) -> VirtualJoystickAxis;

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

    /// Delta value snaped
    pub fn snap_axis(&self) -> Vec2;
}

// Bundle to spawn
struct VirtualJoystickBundle {
    pub fn new(joystick: VirtualJoystickNode) -> Self;

    pub fn set_node(mut self, node: Node) -> Self;

    pub fn set_style(mut self, style: Style) -> Self;

    pub fn set_color(mut self, color: TintColor) -> Self;

    pub fn set_focus_policy(mut self, focus_policy: FocusPolicy) -> Self;

    pub fn set_transform(mut self, transform: Transform) -> Self;

    pub fn set_global_transform(mut self, global_transform: GlobalTransform) -> Self;

    pub fn set_visibility(mut self, visibility: Visibility) -> Self;

    pub fn set_computed_visibility(mut self, computed_visibility: ComputedVisibility) -> Self;

    pub fn set_z_index(mut self, z_index: ZIndex) -> Self;
}

Issues

TODOs

  • Add more documentation
  • Fix movement of Dynamic joystick
You might also like...
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Minecraft using Bevy and Bevy-Meshem

minecraft_bevy Minecraft_bevy was built to showcase bevy_meshem. After a week of developing it has: Chunk loading / unloading each chunk's mesh is bei

A frontend to Assets purchased on Epic Games Store
A frontend to Assets purchased on Epic Games Store

Epic-Asset-Manager A frontend to Assets purchased on Epic Games Store Current Screenshot Install Arch Linux Use the AUR package Build flatpak meson _b

A single-threaded polling-based Rust async executor suitable for use in games, embedded systems or WASM.

simple async local executor An Enlightware® software. Overview A single-threaded polling-based executor suitable for use in games, embedded systems or

A framework for making games using Macroquad.

Omegaquad A framework for making games using Macroquad. After writing maybe 5 games and finding myself always going to the previous project to copy-pa

Synchronize games from other platforms into your Steam library

BoilR Description This little tool will synchronize games from other platforms into your Steam library, using the Steam Shortcuts feature. The goal is

A Rust promise for games and immediate mode GUIs

⌛ poll-promise A Rust promise for games and immediate mode GUIs Description poll-promise is a Rust crate for polling the result of a concurrent (e.g.

A single-threaded executor for deferred async code for games.

This crate provides a single-threaded, sequential, parameterized async runtime. In other words, this creates coroutines, specifically targeting video game logic, though cosync is suitable for creating any sequences of directions which take time.

Comments
  • 2 joysticks type and events issues

    2 joysticks type and events issues

    Hello, thank you for this library!

    I'm trying it in bevy_garage https://github.com/alexichepura/bevy_garage/pull/62

    2 issues:

    • not receiving events if using 2 joysticks (single joystick works well)
    • VirtualJoystickAxis is a resource, so not able to set 2 different types

    Screenshot 2023-04-15 at 11 09 38

    bug enhancement 
    opened by alexichepura 8
  • knob delta calc from zone half

    knob delta calc from zone half

    Hello, normalized delta difference didn't give me desired values. It was always starting at 0.9.., so i just propose what worked for me, is to calculate relative to interactive zone half size.

    opened by alexichepura 1
Owner
Sergio Alejandro Ribera Costa
20yo Enthusiastic developer Linux and Open Source lover I've been trying to make my mark in the world since I was 12 years old
Sergio Alejandro Ribera Costa
An ergonomic physics API for bevy games.

Heron An ergonomic physics API for 2d and 3d bevy games. (powered by rapier) How it looks like fn main() { App::build() .add_plugins(DefaultPlug

Jonathan Cornaz 313 Dec 16, 2022
A simple camera for properly displaying tile-based low resolution pixel perfect 2D games in bevy.

Bevy Tiled Camera A simple camera for properly displaying low resolution pixel perfect 2D games in bevy. The camera will adjust the viewport to scale

sark 10 Oct 5, 2022
A framework for building adventure games in Bevy.

Bevy_adventure A framework for building 3d adventure games in Bevy. preview.mp4 Features Interactive trait is the backbone of the framework, allowing

Hank Jordan 9 Jan 5, 2023
Explicitly set sprite layers for sprites in Bevy games.

extol_sprite_layer lets you specify the drawing order for sprites in your Bevy game using a separate component rather than via the z-coordinate of you

Ash 5 May 2, 2023
Highly customizable splash screen library for Bevy games.

bevy_intro_screen This is a versatile Bevy library designed to create engaging and customizable introductory screens for your game. Initially conceive

Aarav Shah 4 Aug 13, 2024
Hierarchical Task Network Planning deeply integrated with bevy, which I use in my games :P

Note that CI currently tests against a matrix of (windows, mac, linux) * (toolchain stable, nightly) * (cargo build, test, clippy), which ensures vali

null 29 Oct 16, 2024
Pixel-Perfect, 2D Renderer for Bevy that Seamlessly Targets Desktop and Web

bevy_retro ( Screenshot of Bounty Bros. game made with Bevy Retro and Skip'n Go ) Bevy Retro is a 2D, pixel-perfect renderer for Bevy that can target

Katharos Technology 224 Dec 23, 2022
A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it techinically works

rustetris A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it tech

Eric G 3 Oct 15, 2022
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy

Bevy Voxel Cone Tracing bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy. Bevy Version

研究社交 208 Dec 27, 2022