Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions crates/bevy_input/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,80 @@ where
self.just_released.iter()
}
}

#[cfg(test)]
mod test {

#[test]
fn input_test() {
use crate::Input;

/// Used for testing `Input` functionality
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
enum DummyInput {
Input1,
Input2,
}

let mut input = Input::default();

// Test pressing
input.press(DummyInput::Input1);
input.press(DummyInput::Input2);

// Check if they were "just pressed" (pressed on this update)
assert!(input.just_pressed(DummyInput::Input1));
assert!(input.just_pressed(DummyInput::Input2));

// Check if they are also marked as pressed
assert!(input.pressed(DummyInput::Input1));
assert!(input.pressed(DummyInput::Input2));

// Update the `Input` and check press state
input.update();

// Check if they're marked "just pressed"
assert!(!input.just_pressed(DummyInput::Input1));
assert!(!input.just_pressed(DummyInput::Input2));

// Check if they're marked as pressed
assert!(input.pressed(DummyInput::Input1));
assert!(input.pressed(DummyInput::Input2));

// Release the inputs and check state

input.release(DummyInput::Input1);
input.release(DummyInput::Input2);

// Check if they're marked as "just released" (released on this update)
assert!(input.just_released(DummyInput::Input1));
assert!(input.just_released(DummyInput::Input2));

// Check that they're not incorrectly marked as pressed
assert!(!input.pressed(DummyInput::Input1));
assert!(!input.pressed(DummyInput::Input2));

// Update the `Input` and check for removal from `just_released`

input.update();

// Check that they're not incorrectly marked as just released
assert!(!input.just_released(DummyInput::Input1));
assert!(!input.just_released(DummyInput::Input2));

// Set up an `Input` to test resetting.
let mut input = Input::default();

input.press(DummyInput::Input1);
input.release(DummyInput::Input2);

// Reset the `Input` and test it was reset correctly.
input.reset(DummyInput::Input1);
input.reset(DummyInput::Input2);

assert!(!input.just_pressed(DummyInput::Input1));
assert!(!input.pressed(DummyInput::Input1));

assert!(!input.just_released(DummyInput::Input2));
}
}
241 changes: 209 additions & 32 deletions crates/bevy_input/src/touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use bevy_app::{EventReader, Events};
use bevy_ecs::{Local, Res, ResMut};
use bevy_math::Vec2;
use bevy_utils::HashMap;
use core::ops::DerefMut;

/// Represents a touch event
///
Expand Down Expand Up @@ -139,10 +138,8 @@ impl Touches {
self.just_pressed.contains_key(&id)
}

pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> + '_ {
self.just_pressed
.iter()
.map(move |(id, _)| self.pressed.get(id).unwrap())
pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> {
self.just_pressed.values()
}

pub fn get_released(&self, id: u64) -> Option<&Touch> {
Expand All @@ -153,54 +150,234 @@ impl Touches {
self.just_released.contains_key(&id)
}

pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> + '_ {
self.just_released
.iter()
.map(move |(id, _)| self.pressed.get(id).unwrap())
pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> {
self.just_released.values()
}

pub fn just_cancelled(&self, id: u64) -> bool {
self.just_cancelled.contains_key(&id)
}

pub fn iter_just_cancelled(&self) -> impl Iterator<Item = &Touch> + '_ {
self.just_cancelled
.iter()
.map(move |(id, _)| self.pressed.get(id).unwrap())
pub fn iter_just_cancelled(&self) -> impl Iterator<Item = &Touch> {
self.just_cancelled.values()
}
}

/// Updates the Touches resource with the latest TouchInput events
pub fn touch_screen_input_system(
mut state: Local<TouchSystemState>,
mut touch_state: ResMut<Touches>,
touch_input_events: Res<Events<TouchInput>>,
) {
let touch_state = touch_state.deref_mut();
touch_state.just_pressed.clear();
touch_state.just_released.clear();
for event in state.touch_event_reader.iter(&touch_input_events) {
fn process_touch_event(&mut self, event: &TouchInput) {
match event.phase {
TouchPhase::Started => {
touch_state.pressed.insert(event.id, event.into());
touch_state.just_pressed.insert(event.id, event.into());
self.pressed.insert(event.id, event.into());
self.just_pressed.insert(event.id, event.into());
}
TouchPhase::Moved => {
let mut new_touch = touch_state.pressed.get(&event.id).cloned().unwrap();
let mut new_touch = self.pressed.get(&event.id).cloned().unwrap();
new_touch.previous_position = new_touch.position;
new_touch.previous_force = new_touch.force;
new_touch.position = event.position;
new_touch.force = event.force;
touch_state.pressed.insert(event.id, new_touch);
self.pressed.insert(event.id, new_touch);
}
TouchPhase::Ended => {
touch_state.just_released.insert(event.id, event.into());
touch_state.pressed.remove_entry(&event.id);
self.just_released.insert(event.id, event.into());
self.pressed.remove_entry(&event.id);
}
TouchPhase::Cancelled => {
touch_state.just_cancelled.insert(event.id, event.into());
touch_state.pressed.remove_entry(&event.id);
self.just_cancelled.insert(event.id, event.into());
self.pressed.remove_entry(&event.id);
}
};
}

fn update(&mut self) {
self.just_pressed.clear();
self.just_released.clear();
self.just_cancelled.clear();
}
}

/// Updates the Touches resource with the latest TouchInput events
pub fn touch_screen_input_system(
mut state: Local<TouchSystemState>,
mut touch_state: ResMut<Touches>,
touch_input_events: Res<Events<TouchInput>>,
) {
touch_state.update();

for event in state.touch_event_reader.iter(&touch_input_events) {
touch_state.process_touch_event(event);
}
}

#[cfg(test)]
mod test {

#[test]
fn touch_update() {
use crate::{touch::Touch, Touches};
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_event = Touch {
id: 4,
start_position: Vec2::new(0.0, 0.0),
start_force: None,
previous_position: Vec2::new(0.0, 0.0),
previous_force: None,
position: Vec2::new(0.0, 0.0),
force: None,
};

// Add a touch to `just_pressed`, 'just_released', and 'just cancelled'

touches.just_pressed.insert(4, touch_event);
touches.just_released.insert(4, touch_event);
touches.just_cancelled.insert(4, touch_event);

touches.update();

// Verify that all the `just_x` maps are cleared
assert!(touches.just_pressed.is_empty());
assert!(touches.just_released.is_empty());
assert!(touches.just_cancelled.is_empty());
}

#[test]
fn touch_process() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_math::Vec2;

let mut touches = Touches::default();

// Test adding a `TouchPhase::Started`

let touch_event = TouchInput {
phase: TouchPhase::Started,
position: Vec2::new(4.0, 4.0),
force: None,
id: 4,
};

touches.update();
touches.process_touch_event(&touch_event);

assert!(touches.pressed.get(&touch_event.id).is_some());
assert!(touches.just_pressed.get(&touch_event.id).is_some());

// Test adding a `TouchPhase::Moved`

let moved_touch_event = TouchInput {
phase: TouchPhase::Moved,
position: Vec2::new(5.0, 5.0),
force: None,
id: touch_event.id,
};

touches.update();
touches.process_touch_event(&moved_touch_event);

assert_eq!(
touches
.pressed
.get(&moved_touch_event.id)
.expect("Missing from pressed after move.")
.previous_position,
touch_event.position
);

// Test cancelling an event

let cancel_touch_event = TouchInput {
phase: TouchPhase::Cancelled,
position: Vec2::new(1.0, 1.0),
force: None,
id: touch_event.id,
};

touches.update();
touches.process_touch_event(&cancel_touch_event);

assert!(touches.just_cancelled.get(&cancel_touch_event.id).is_some());
assert!(touches.pressed.get(&cancel_touch_event.id).is_none());

// Test ending an event

let end_touch_event = TouchInput {
phase: TouchPhase::Ended,
position: Vec2::new(4.0, 4.0),
force: None,
id: 4,
};

touches.update();
touches.process_touch_event(&touch_event);
touches.process_touch_event(&end_touch_event);

assert!(touches.just_released.get(&touch_event.id).is_some());
assert!(touches.pressed.get(&touch_event.id).is_none());
}

#[test]
fn touch_pressed() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_event = TouchInput {
phase: TouchPhase::Started,
position: Vec2::new(4.0, 4.0),
force: None,
id: 4,
};

// Register the touch and test that it was registered correctly
touches.process_touch_event(&touch_event);

assert!(touches.get_pressed(touch_event.id).is_some());
assert!(touches.just_pressed(touch_event.id));
assert_eq!(touches.iter().count(), 1);
}

#[test]
fn touch_released() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_event = TouchInput {
phase: TouchPhase::Ended,
position: Vec2::new(4.0, 4.0),
force: None,
id: 4,
};

// Register the touch and test that it was registered correctly
touches.process_touch_event(&touch_event);

assert!(touches.get_released(touch_event.id).is_some());
assert!(touches.just_released(touch_event.id));
assert_eq!(touches.iter_just_released().count(), 1);
}

#[test]
fn touch_cancelled() {
use crate::{touch::TouchPhase, TouchInput, Touches};
use bevy_math::Vec2;

let mut touches = Touches::default();

let touch_event = TouchInput {
phase: TouchPhase::Cancelled,
position: Vec2::new(4.0, 4.0),
force: None,
id: 4,
};

// Register the touch and test that it was registered correctly
touches.process_touch_event(&touch_event);

assert!(touches.just_cancelled(touch_event.id));
assert_eq!(touches.iter_just_cancelled().count(), 1);
}
}
20 changes: 20 additions & 0 deletions crates/bevy_math/src/face_toward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,23 @@ impl FaceToward for Mat4 {
)
}
}

#[cfg(test)]
mod test {
#[test]
fn face_toward_mat4() {
use crate::{FaceToward, Mat4, Vec3, Vec4};

// Completely arbitrary arguments
let matrix = Mat4::face_toward(
Vec3::new(50.0, 60.0, 0.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);

assert_eq!(matrix.x_axis, Vec4::new(0.0, 0.0, -1.0, -0.0));
assert_eq!(matrix.y_axis, Vec4::new(-0.7682213, 0.6401844, 0.0, 0.0));
assert_eq!(matrix.z_axis, Vec4::new(0.6401844, 0.7682213, 0.0, 0.0));
assert_eq!(matrix.w_axis, Vec4::new(50.0, 60.0, 0.0, 1.0));
}
}