From f020c584dafa429c67f7b054cc085e247b4a3e50 Mon Sep 17 00:00:00 2001 From: Sergio Ribera Date: Sat, 18 Nov 2023 03:41:33 -0400 Subject: [PATCH] feat: migrate to bevy 0.12 --- Cargo.toml | 8 +- src/input.rs | 18 ++-- src/joystick.rs | 277 +++++++++++++++++++----------------------------- src/lib.rs | 43 ++++---- 4 files changed, 141 insertions(+), 205 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3dec577..19dd257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,12 +26,12 @@ inspect = ["bevy-inspector-egui"] serde = ["dep:serde"] [dependencies] -bevy = { version = "0.11", default-features = false, features = [ +bevy = { version = "0.12", default-features = false, features = [ "bevy_render", - "bevy_ui" + "bevy_ui", ] } -bevy-inspector-egui = { version = "0.19", optional = true } +bevy-inspector-egui = { version = "0.21", optional = true } serde = { version = "^1", features = ["derive"], optional = true } [dev-dependencies] -bevy = "0.11" +bevy = "0.12" diff --git a/src/input.rs b/src/input.rs index 600c7c1..bbfa9e8 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,14 +1,12 @@ -use std::hash::Hash; - use bevy::{ input::{mouse::MouseButtonInput, touch::TouchPhase, ButtonState}, prelude::*, - reflect::TypePath, window::PrimaryWindow, }; +use crate::VirtualJoystickID; use crate::{ - joystick::VirtualJoystickKnob, VirtualJoystickEvent, VirtualJoystickEventType, + joystick::VirtualJoystickData, VirtualJoystickEvent, VirtualJoystickEventType, VirtualJoystickNode, VirtualJoystickType, }; @@ -30,14 +28,12 @@ fn is_some_and(opt: Option, cb: impl FnOnce(T) -> bool) -> bool { false } -pub fn update_input< - S: Hash + Sync + Send + Clone + Default + Reflect + TypePath + FromReflect + 'static, ->( +pub fn update_input( mut input_events: EventReader, mut send_values: EventWriter>, - mut joysticks: Query<(&VirtualJoystickNode, &mut VirtualJoystickKnob)>, + mut joysticks: Query<(&VirtualJoystickNode, &mut VirtualJoystickData)>, ) { - let input_events = input_events.iter().collect::>(); + let input_events = input_events.read().collect::>(); for (node, mut knob) in joysticks.iter_mut() { for event in &input_events { @@ -121,7 +117,7 @@ pub fn update_joystick( mut send_values: EventWriter, ) { let touches = touch_events - .iter() + .read() .map(|e| (e.id, e.phase, e.position)) .collect::>(); @@ -152,7 +148,7 @@ pub fn update_joystick_by_mouse( let window = windows.single(); let pos = window.cursor_position().unwrap_or(Vec2::ZERO); - for mousebtn in mousebtn_evr.iter() { + for mousebtn in mousebtn_evr.read() { // End drag if mousebtn.button == MouseButton::Left && mousebtn.state == ButtonState::Released { send_values.send(InputEvent::EndDrag { id: 0, pos }); diff --git a/src/joystick.rs b/src/joystick.rs index ecc0f28..f6d48f6 100644 --- a/src/joystick.rs +++ b/src/joystick.rs @@ -1,94 +1,61 @@ -use std::hash::Hash; - use bevy::{ prelude::*, render::Extract, - ui::{ - ContentSize, ExtractedUiNode, ExtractedUiNodes, FocusPolicy, RelativeCursorPosition, - UiStack, - }, + ui::{ExtractedUiNodes, RelativeCursorPosition}, }; #[cfg(feature = "inspect")] use bevy_inspector_egui::prelude::*; -use crate::{VirtualJoystickAxis, VirtualJoystickType}; +use crate::{VirtualJoystickAxis, VirtualJoystickID, VirtualJoystickType}; -/// The tint color of the image -/// -/// When combined with [`VirtualJoystickNode`], tints the provided texture, while still -/// respecting transparent areas. -#[derive(Component, Copy, Clone, Debug, Reflect)] +#[derive(Component, Clone, Debug, Default, Reflect)] #[reflect(Component, Default)] #[cfg_attr(feature = "inspect", derive(InspectorOptions))] #[cfg_attr(feature = "inspect", reflect(InspectorOptions))] -pub struct TintColor(pub Color); - -impl TintColor { - pub const DEFAULT: Self = Self(Color::WHITE); -} - -impl Default for TintColor { - fn default() -> Self { - Self::DEFAULT - } -} +pub struct VirtualJoystickInteractionArea; -impl From for TintColor { - fn from(color: Color) -> Self { - Self(color) - } -} +#[derive(Component, Copy, Clone, Debug, Default, Reflect)] +#[reflect(Component, Default)] +#[cfg_attr(feature = "inspect", derive(InspectorOptions))] +#[cfg_attr(feature = "inspect", reflect(InspectorOptions))] +pub struct VirtualJoystickUIKnob; #[derive(Component, Copy, Clone, Debug, Default, Reflect)] #[reflect(Component, Default)] #[cfg_attr(feature = "inspect", derive(InspectorOptions))] #[cfg_attr(feature = "inspect", reflect(InspectorOptions))] -pub struct VirtualJoystickInteractionArea; +pub struct VirtualJoystickUIBackground; #[derive(Bundle, Debug, Default)] -pub struct VirtualJoystickBundle< - S: Hash + Sync + Send + Clone + Default + Reflect + FromReflect + 'static, -> { +pub struct VirtualJoystickBundle { /// Describes the size of the node pub(crate) node: Node, /// Describes the style including flexbox settings pub(crate) style: Style, - /// The calculated size based on the given image - pub(crate) calculated_size: ContentSize, - /// The tint color of the image - pub(crate) color: TintColor, /// The texture atlas image of the node pub(crate) joystick: VirtualJoystickNode, - /// Whether this node should block interaction with lower nodes - pub(crate) focus_policy: FocusPolicy, /// The transform of the node pub(crate) transform: Transform, /// The global transform of the node pub(crate) global_transform: GlobalTransform, /// Describes the visibility properties of the node - pub(crate) visibility: Visibility, + pub visibility: Visibility, + /// Inherited visibility of an entity. + pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering - pub(crate) computed_visibility: ComputedVisibility, + pub view_visibility: ViewVisibility, /// Indicates the depth at which the node should appear in the UI pub(crate) z_index: ZIndex, - pub(crate) knob_data: VirtualJoystickKnob, + pub(crate) knob_data: VirtualJoystickData, pub(crate) cursor_pos: RelativeCursorPosition, } #[derive(Component, Clone, Debug, Default, Reflect)] #[reflect(Component, Default)] -pub struct VirtualJoystickNode< - S: Hash + Sync + Send + Clone + Default + Reflect + FromReflect + 'static, -> { +pub struct VirtualJoystickNode { /// Identifier of joystick pub id: S, - /// Image for background or border image on joystick - pub border_image: Handle, - /// Image for handler knob on joystick - pub knob_image: Handle, - /// Size for knob on joystick - pub knob_size: Vec2, /// Zone to ignore movement pub dead_zone: f32, /// Define Axis for this joystick @@ -99,7 +66,7 @@ pub struct VirtualJoystickNode< #[derive(Component, Clone, Debug, Default, Reflect)] #[reflect(Component, Default)] -pub struct VirtualJoystickKnob { +pub struct VirtualJoystickData { pub id_drag: Option, pub dead_zone: f32, pub base_pos: Vec2, @@ -109,9 +76,7 @@ pub struct VirtualJoystickKnob { pub interactable_zone_rect: Rect, } -impl - VirtualJoystickBundle -{ +impl VirtualJoystickBundle { pub fn new(joystick: VirtualJoystickNode) -> Self { Self { joystick, @@ -129,16 +94,6 @@ impl self } - pub fn set_color(mut self, color: TintColor) -> Self { - self.color = color; - self - } - - pub fn set_focus_policy(mut self, focus_policy: FocusPolicy) -> Self { - self.focus_policy = focus_policy; - self - } - pub fn set_transform(mut self, transform: Transform) -> Self { self.transform = transform; self @@ -149,16 +104,6 @@ impl self } - pub fn set_visibility(mut self, visibility: Visibility) -> Self { - self.visibility = visibility; - self - } - - pub fn set_computed_visibility(mut self, computed_visibility: ComputedVisibility) -> Self { - self.computed_visibility = computed_visibility; - self - } - pub fn set_z_index(mut self, z_index: ZIndex) -> Self { self.z_index = z_index; self @@ -166,118 +111,114 @@ impl } #[allow(clippy::type_complexity)] -pub fn extract_joystick_node< - S: Hash + Sync + Send + Clone + Default + Reflect + FromReflect + 'static, ->( +pub fn extract_joystick_node( mut extracted_uinodes: ResMut, - images: Extract>>, - ui_stack: Extract>, + knob_ui_query: Extract>>, + bg_ui_query: Extract>>, uinode_query: Extract< Query<( &Node, &GlobalTransform, - &TintColor, &VirtualJoystickNode, - &ComputedVisibility, - &VirtualJoystickKnob, + &Visibility, + &InheritedVisibility, + &ViewVisibility, + &VirtualJoystickData, )>, >, ) { - for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() { - if let Ok((uinode, global_transform, color, joystick_node, visibility, data)) = - uinode_query.get(*entity) + for (entity, parent) in &knob_ui_query { + if let Ok(( + uinode, + global_transform, + joystick_node, + visibility, + inherited_visibility, + view_visibility, + data, + )) = uinode_query.get(**parent) { - if !visibility.is_visible() + if visibility == Visibility::Hidden + || !inherited_visibility.get() + || !view_visibility.get() || uinode.size().x == 0. || uinode.size().y == 0. - || color.0.a() == 0.0 - || !images.contains(&joystick_node.border_image) - || !images.contains(&joystick_node.knob_image) || data.id_drag.is_none() && joystick_node.behaviour == VirtualJoystickType::Dynamic { continue; } - let container_rect = Rect { - max: uinode.size(), - ..default() - }; - - let border_pos = match joystick_node.behaviour { - VirtualJoystickType::Fixed => global_transform - .compute_matrix() - .transform_point3((container_rect.center() - (uinode.size() / 2.)).extend(0.)), - VirtualJoystickType::Floating => { - if data.id_drag.is_none() { - global_transform.compute_matrix().transform_point3( - (container_rect.center() - (uinode.size() / 2.)).extend(0.), - ) - } else { - data.start_pos.extend(0.) - } - } - VirtualJoystickType::Dynamic => data.base_pos.extend(0.), - }; - - extracted_uinodes.uinodes.push(ExtractedUiNode { - stack_index, - transform: Mat4::from_translation(border_pos), - color: color.0, - rect: container_rect, - image: joystick_node.border_image.clone(), - atlas_size: None, - clip: None, - flip_x: false, - flip_y: false, - }); - - let rect = Rect { - max: joystick_node.knob_size, - ..default() - }; - + let base_pos = get_base_pos(uinode, joystick_node.behaviour, data, global_transform); let radius = uinode.size().x / 2.; - let delta = data.start_pos - data.current_pos; - let angle = delta.y.atan2(delta.x); - let dist = f32::min(delta.length(), radius); - - let x = dist * angle.cos(); - let y = dist * angle.sin(); - - let knob_pos = match joystick_node.behaviour { - VirtualJoystickType::Fixed => global_transform.compute_matrix().transform_point3( - (container_rect.center() - - (uinode.size() / 2.) - - joystick_node.axis.handle_xy(x, y)) - .extend(0.), - ), - VirtualJoystickType::Floating => { - if data.id_drag.is_none() { - global_transform.compute_matrix().transform_point3( - (container_rect.center() - - (uinode.size() / 2.) - - joystick_node.axis.handle_xy(x, y)) - .extend(0.), - ) - } else { - (data.start_pos - joystick_node.axis.handle_xy(x, y)).extend(0.) - } - } - VirtualJoystickType::Dynamic => { - (data.base_pos - joystick_node.axis.handle_xy(x, y)).extend(0.) - } - }; + // ui is y down, so we flip + let pos = -data.delta * radius; + let knob_pos = base_pos + joystick_node.axis.handle_vec3(pos.extend(0.)); + + extracted_uinodes + .uinodes + .entry(entity) + .and_modify(|node| { + node.transform = Mat4::from_translation(knob_pos); + }); + } + } - extracted_uinodes.uinodes.push(ExtractedUiNode { - rect, - stack_index, - transform: Mat4::from_translation(knob_pos), - color: color.0, - image: joystick_node.knob_image.clone(), - atlas_size: None, - clip: None, - flip_x: false, - flip_y: false, - }); + for (entity, parent) in &bg_ui_query { + if let Ok(( + uinode, + global_transform, + joystick_node, + visibility, + inherited_visibility, + view_visibility, + data, + )) = uinode_query.get(**parent) + { + if visibility == Visibility::Hidden + || !inherited_visibility.get() + || !view_visibility.get() + || uinode.size().x == 0. + || uinode.size().y == 0. + || data.id_drag.is_none() && joystick_node.behaviour == VirtualJoystickType::Dynamic + { + continue; + } + let pos = get_base_pos(uinode, joystick_node.behaviour, data, global_transform); + extracted_uinodes + .uinodes + .entry(entity) + .and_modify(|node| { + node.transform = Mat4::from_translation(pos); + }); } } } + +fn get_base_pos( + uinode: &Node, + behaviour: VirtualJoystickType, + joystick: &VirtualJoystickData, + global_transform: &GlobalTransform, +) -> Vec3 { + let container_rect = Rect { + max: uinode.size(), + ..default() + }; + + let border_pos = match behaviour { + VirtualJoystickType::Fixed => global_transform + .compute_matrix() + .transform_point3((container_rect.center() - (uinode.size() / 2.)).extend(0.)), + VirtualJoystickType::Floating => { + if joystick.id_drag.is_none() { + global_transform + .compute_matrix() + .transform_point3((container_rect.center() - (uinode.size() / 2.)).extend(0.)) + } else { + joystick.start_pos.extend(0.) + } + } + VirtualJoystickType::Dynamic => joystick.base_pos.extend(0.), + }; + + border_pos +} diff --git a/src/lib.rs b/src/lib.rs index 4348596..5c29ae1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,24 +14,32 @@ mod joystick; pub use behaviour::{VirtualJoystickAxis, VirtualJoystickType}; use input::{run_if_pc, update_input, update_joystick, update_joystick_by_mouse, InputEvent}; pub use joystick::{ - TintColor, VirtualJoystickBundle, VirtualJoystickInteractionArea, VirtualJoystickNode, + VirtualJoystickBundle, VirtualJoystickInteractionArea, VirtualJoystickNode, + VirtualJoystickUIBackground, VirtualJoystickUIKnob, }; -use joystick::{extract_joystick_node, VirtualJoystickKnob}; +use joystick::{extract_joystick_node, VirtualJoystickData}; #[derive(Default)] pub struct VirtualJoystickPlugin { _marker: PhantomData, } -impl Plugin - for VirtualJoystickPlugin +pub trait VirtualJoystickID: + Hash + Sync + Send + Clone + Default + Reflect + TypePath + FromReflect + 'static { +} + +impl + VirtualJoystickID for S +{ +} + +impl Plugin for VirtualJoystickPlugin { fn build(&self, app: &mut bevy::prelude::App) { - app.register_type::() - .register_type::() + app.register_type::() .register_type::>() - .register_type::() + .register_type::() .register_type::() .register_type::() .register_type::() @@ -55,10 +63,7 @@ impl.before(UiSystem::Layout), ); - let render_app = match app.get_sub_app_mut(RenderApp) { - Ok(render_app) => render_app, - Err(_) => return, - }; + let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { return; }; render_app.add_systems( ExtractSchedule, extract_joystick_node::.after(RenderUiSystem::ExtractNode), @@ -66,14 +71,12 @@ impl( +fn joystick_image_node_system( interaction_area: Query<(&Node, With)>, mut joystick: Query<( &Transform, &VirtualJoystickNode, - &mut VirtualJoystickKnob, + &mut VirtualJoystickData, )>, ) { let interaction_area = interaction_area @@ -100,10 +103,8 @@ pub enum VirtualJoystickEventType { Up, } -#[derive(Event)] -pub struct VirtualJoystickEvent< - S: Hash + Sync + Send + Clone + Default + Reflect + 'static + TypePath, -> { +#[derive(Event, Debug)] +pub struct VirtualJoystickEvent { id: S, event: VirtualJoystickEventType, value: Vec2, @@ -111,9 +112,7 @@ pub struct VirtualJoystickEvent< axis: VirtualJoystickAxis, } -impl - VirtualJoystickEvent -{ +impl VirtualJoystickEvent { /// Get ID of joystick throw event pub fn id(&self) -> S { self.id.clone()