Skip to content

Commit

Permalink
feat: touch wip
Browse files Browse the repository at this point in the history
  • Loading branch information
simonas-notcat committed Dec 15, 2023
1 parent d57cc36 commit d2506ed
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "graph-view"
version = "0.1.17"
version = "0.1.18"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod identifiers;
mod keyboard;
mod resources;
mod simulation;
mod touch;
mod util;

use assets::AssetsPlugin;
Expand All @@ -20,6 +21,7 @@ use identifiers::IdentifiersPlugin;
use keyboard::KeyboardPlugin;
use resources::Configuration;
use simulation::SimulationPlugin;
use touch::TouchCameraPlugin;

fn main() {
App::new()
Expand All @@ -40,6 +42,7 @@ fn main() {
.add_plugins(EguiPlugin)
.add_plugins(DefaultInspectorConfigPlugin)
.add_plugins(PanOrbitCameraPlugin)
.add_plugins(TouchCameraPlugin::default())
.add_plugins(KeyboardPlugin)
.add_plugins(WorldInspectorPlugin::default().run_if(input_toggle_active(false, KeyCode::W)))
.add_plugins(SimulationPlugin)
Expand Down
159 changes: 159 additions & 0 deletions src/touch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// https://github.com/d-bucur/bevy_touch_camera/blob/main/src/plugin.rs
use bevy::{input::touch, prelude::*, time::Time};
use bevy_panorbit_camera::PanOrbitCamera;

/// A plugin that will update camera movement based on `Touch` gestures that Bevy provides
#[derive(Default)]
pub struct TouchCameraPlugin {
pub config: TouchCameraConfig,
}

impl Plugin for TouchCameraPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(TouchTracker::default())
.insert_resource(self.config.clone())
.add_systems(Update, touch_pan_zoom);
}
}

/// Contains the configuration parameters for the plugin.
/// A copy of this will be attached as a `Resource` to the `App`.
#[derive(Resource, Clone)]
pub struct TouchCameraConfig {
/// How far the camera will move relative to the touch drag distance. Higher is faster
pub drag_sensitivity: f32,
/// How much the camera will zoom relative to the pinch distance using two fingers. Higher means faster.
/// At the moment the default is very low at 0.005 but this might change in the future
pub zoom_sensitivity: f32,
/// Minimum time before starting to pan in seconds. Useful to avoid panning on short taps
pub touch_time_min: f32,
/// Tolerance for pinch fingers moving in opposite directions (-1. .. 1.).
/// Higher values make it more tolerant.
/// Very low values not recommended as it would be overly sensitive
pub opposites_tolerance: f32,
}

impl Default for TouchCameraConfig {
fn default() -> Self {
Self {
drag_sensitivity: 1.,
zoom_sensitivity: 0.005,
touch_time_min: 0.01,
opposites_tolerance: 0.,
}
}
}

/// This is the tag that the plugin will scan for and update its `Camera` component.
/// You can either attach it manually to your camera, or the plugin will try to attach it
/// to the default camera in the `PostStartup` schedule
#[derive(Component)]
pub struct TouchCameraTag;

#[derive(PartialEq, Default)]
enum GestureType {
#[default]
None,
Pan,
Pinch,
PinchCancelled,
}

#[derive(Resource, Default)]
struct TouchTracker {
pub camera_start_pos: Vec3,
pub time_start_touch: f32,
pub gesture_type: GestureType,

// Keeps track of position on last frame.
// This is different from Touch.last_position as that only updates when there has been a movement
pub last_touch_a: Option<Vec2>,
pub last_touch_b: Option<Vec2>,
}

fn touch_pan_zoom(
touches_res: Res<Touches>,
mut camera_q: Query<(&mut PanOrbitCamera, &Transform)>,
mut tracker: ResMut<TouchTracker>,
config: Res<TouchCameraConfig>,
time: Res<Time>,
) {
let Ok((mut camera, camera_transform)) = camera_q.get_single_mut() else {
return;
};

let touches: Vec<&touch::Touch> = touches_res.iter().collect();

if touches.is_empty() {
tracker.gesture_type = GestureType::None;
tracker.last_touch_a = None;
tracker.last_touch_b = None;
return;
}

if touches_res.any_just_released() {
tracker.gesture_type = GestureType::PinchCancelled;
tracker.last_touch_a = None;
tracker.last_touch_b = None;
}

if touches.len() == 2 {
tracker.gesture_type = GestureType::Pinch;
// complicated way to reset previous position to prevent some bugs. Should simplify
let last_a = if tracker.last_touch_b.is_none() {
touches[0].position()
} else {
tracker.last_touch_a.unwrap_or(touches[0].position())
};
let last_b = if tracker.last_touch_b.is_none() {
touches[1].position()
} else {
tracker.last_touch_b.unwrap_or(touches[1].position())
};

let delta_a = touches[0].position() - last_a;
let delta_b = touches[1].position() - last_b;
let delta_total = (delta_a + delta_b).length();
let dot_delta = delta_a.dot(delta_b);
if dot_delta > config.opposites_tolerance {
return;
}

let distance_current = touches[0].position() - touches[1].position();
let distance_prev = touches[0].previous_position() - touches[1].previous_position();
let pinch_direction = distance_prev.length() - distance_current.length();
let Some(radius) = camera.radius else {
return;
};
camera.target_radius +=
pinch_direction.signum() * delta_total * config.zoom_sensitivity * radius;

tracker.last_touch_a = Some(touches[0].position());
tracker.last_touch_b = Some(touches[1].position());
} else if touches.len() == 1
&& matches!(tracker.gesture_type, GestureType::None | GestureType::Pan)
{
if tracker.gesture_type == GestureType::None {
tracker.camera_start_pos = camera_transform.translation;
tracker.time_start_touch = time.elapsed_seconds();
}
tracker.gesture_type = GestureType::Pan;
let time_since_start = time.elapsed_seconds() - tracker.time_start_touch;
if time_since_start < config.touch_time_min {
return;
}

camera.target_alpha += touches[0].distance().y.to_radians();
camera.target_beta += touches[0].distance().x.to_radians();

// let distance = Vec3::new(touches[0].distance().x, -touches[0].distance().y, 0.);
// let Some(radius) = camera.radius else {
// return;
// };

// transform.translation =
// tracker.camera_start_pos - config.drag_sensitivity * distance * radius;
tracker.last_touch_a = Some(touches[0].position());
tracker.last_touch_b = None;
}
}

0 comments on commit d2506ed

Please sign in to comment.