Skip to content

Commit

Permalink
Add TripleAxislike (#609)
Browse files Browse the repository at this point in the history
* Add `TripleAxislike`

* Apply suggestion

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
  • Loading branch information
Shute052 and alice-i-cecile authored Aug 25, 2024
1 parent e7a6e76 commit 15a893a
Show file tree
Hide file tree
Showing 15 changed files with 869 additions and 28 deletions.
9 changes: 9 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Version 0.15.1

### Enhancements (0.15.1)

- added `TripleAxislike` trait for inputs that track all X, Y, and Z axes.
- added `KeyboardVirtualDPad3D` that consists of six `KeyCode`s to represent a triple-axis-like input.
- added `TripleAxislikeChord` that groups a `Buttonlike` and a `TripleAxislike` together.
- added related variants such as:
- `InputControlType::TripleAxis`
- `ActionDiff::TripleAxisChanged`

### Usability (0.15.1)

#### InputMap
Expand Down
71 changes: 69 additions & 2 deletions src/action_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use bevy::{
entity::{Entity, MapEntities},
event::Event,
},
math::Vec2,
math::{Vec2, Vec3},
prelude::{EntityMapper, EventWriter, Query, Res},
utils::{HashMap, HashSet},
};
Expand Down Expand Up @@ -50,6 +50,13 @@ pub enum ActionDiff<A: Actionlike> {
/// The new value of the axes
axis_pair: Vec2,
},
/// The axis pair of the action changed
TripleAxisChanged {
/// The value of the action
action: A,
/// The new value of the axes
axis_triple: Vec3,
},
}

/// Will store an `ActionDiff` as well as what generated it (either an Entity, or nothing if the
Expand Down Expand Up @@ -83,6 +90,7 @@ pub struct SummarizedActionState<A: Actionlike> {
button_state_map: HashMap<Entity, HashMap<A, bool>>,
axis_state_map: HashMap<Entity, HashMap<A, f32>>,
dual_axis_state_map: HashMap<Entity, HashMap<A, Vec2>>,
triple_axis_state_map: HashMap<Entity, HashMap<A, Vec3>>,
}

impl<A: Actionlike> SummarizedActionState<A> {
Expand All @@ -94,10 +102,12 @@ impl<A: Actionlike> SummarizedActionState<A> {
let button_entities = self.button_state_map.keys();
let axis_entities = self.axis_state_map.keys();
let dual_axis_entities = self.dual_axis_state_map.keys();
let triple_axis_entities = self.triple_axis_state_map.keys();

entities.extend(button_entities);
entities.extend(axis_entities);
entities.extend(dual_axis_entities);
entities.extend(triple_axis_entities);

entities
}
Expand All @@ -110,11 +120,13 @@ impl<A: Actionlike> SummarizedActionState<A> {
let mut button_state_map = HashMap::default();
let mut axis_state_map = HashMap::default();
let mut dual_axis_state_map = HashMap::default();
let mut triple_axis_state_map = HashMap::default();

if let Some(global_action_state) = global_action_state {
let mut per_entity_button_state = HashMap::default();
let mut per_entity_axis_state = HashMap::default();
let mut per_entity_dual_axis_state = HashMap::default();
let mut per_entity_triple_axis_state = HashMap::default();

for (action, action_data) in global_action_state.all_action_data() {
match &action_data.kind_data {
Expand All @@ -127,18 +139,24 @@ impl<A: Actionlike> SummarizedActionState<A> {
ActionKindData::DualAxis(dual_axis_data) => {
per_entity_dual_axis_state.insert(action.clone(), dual_axis_data.pair);
}
ActionKindData::TripleAxis(triple_axis_data) => {
per_entity_triple_axis_state
.insert(action.clone(), triple_axis_data.triple);
}
}
}

button_state_map.insert(Entity::PLACEHOLDER, per_entity_button_state);
axis_state_map.insert(Entity::PLACEHOLDER, per_entity_axis_state);
dual_axis_state_map.insert(Entity::PLACEHOLDER, per_entity_dual_axis_state);
triple_axis_state_map.insert(Entity::PLACEHOLDER, per_entity_triple_axis_state);
}

for (entity, action_state) in action_state_query.iter() {
let mut per_entity_button_state = HashMap::default();
let mut per_entity_axis_state = HashMap::default();
let mut per_entity_dual_axis_state = HashMap::default();
let mut per_entity_triple_axis_state = HashMap::default();

for (action, action_data) in action_state.all_action_data() {
match &action_data.kind_data {
Expand All @@ -151,18 +169,24 @@ impl<A: Actionlike> SummarizedActionState<A> {
ActionKindData::DualAxis(dual_axis_data) => {
per_entity_dual_axis_state.insert(action.clone(), dual_axis_data.pair);
}
ActionKindData::TripleAxis(triple_axis_data) => {
per_entity_triple_axis_state
.insert(action.clone(), triple_axis_data.triple);
}
}
}

button_state_map.insert(entity, per_entity_button_state);
axis_state_map.insert(entity, per_entity_axis_state);
dual_axis_state_map.insert(entity, per_entity_dual_axis_state);
triple_axis_state_map.insert(entity, per_entity_triple_axis_state);
}

Self {
button_state_map,
axis_state_map,
dual_axis_state_map,
triple_axis_state_map,
}
}

Expand Down Expand Up @@ -222,6 +246,22 @@ impl<A: Actionlike> SummarizedActionState<A> {
})
}

/// Generates an [`ActionDiff`] for triple axis data,
/// if the triple axis has changed state.
pub fn triple_axis_diff(
action: A,
previous_triple_axis: Option<Vec3>,
current_triple_axis: Option<Vec3>,
) -> Option<ActionDiff<A>> {
let previous_triple_axis = previous_triple_axis.unwrap_or_default();
let current_triple_axis = current_triple_axis?;

(previous_triple_axis != current_triple_axis).then(|| ActionDiff::TripleAxisChanged {
action,
axis_triple: current_triple_axis,
})
}

/// Generates all [`ActionDiff`]s for a single entity.
pub fn entity_diffs(&self, entity: &Entity, previous: &Self) -> Vec<ActionDiff<A>> {
let mut action_diffs = Vec::new();
Expand Down Expand Up @@ -273,6 +313,23 @@ impl<A: Actionlike> SummarizedActionState<A> {
}
}

if let Some(current_triple_axis_state) = self.triple_axis_state_map.get(entity) {
let previous_triple_axis_state = previous.triple_axis_state_map.get(entity);
for (action, current_triple_axis) in current_triple_axis_state {
let previous_triple_axis = previous_triple_axis_state
.and_then(|previous_triple_axis_state| previous_triple_axis_state.get(action))
.copied();

if let Some(diff) = Self::triple_axis_diff(
action.clone(),
previous_triple_axis,
Some(*current_triple_axis),
) {
action_diffs.push(diff);
}
}
}

action_diffs
}

Expand Down Expand Up @@ -300,6 +357,7 @@ impl<A: Actionlike> Default for SummarizedActionState<A> {
button_state_map: Default::default(),
axis_state_map: Default::default(),
dual_axis_state_map: Default::default(),
triple_axis_state_map: Default::default(),
}
}
}
Expand All @@ -318,20 +376,24 @@ mod tests {
Axis,
#[actionlike(DualAxis)]
DualAxis,
#[actionlike(TripleAxis)]
TripleAxis,
}

fn test_action_state() -> ActionState<TestAction> {
let mut action_state = ActionState::default();
action_state.press(&TestAction::Button);
action_state.set_value(&TestAction::Axis, 0.3);
action_state.set_axis_pair(&TestAction::DualAxis, Vec2::new(0.5, 0.7));
action_state.set_axis_triple(&TestAction::TripleAxis, Vec3::new(0.5, 0.7, 0.9));
action_state
}

fn expected_summary(entity: Entity) -> SummarizedActionState<TestAction> {
let mut button_state_map = HashMap::default();
let mut axis_state_map = HashMap::default();
let mut dual_axis_state_map = HashMap::default();
let mut triple_axis_state_map = HashMap::default();

let mut global_button_state = HashMap::default();
global_button_state.insert(TestAction::Button, true);
Expand All @@ -345,10 +407,15 @@ mod tests {
global_dual_axis_state.insert(TestAction::DualAxis, Vec2::new(0.5, 0.7));
dual_axis_state_map.insert(entity, global_dual_axis_state);

let mut global_triple_axis_state = HashMap::default();
global_triple_axis_state.insert(TestAction::TripleAxis, Vec3::new(0.5, 0.7, 0.9));
triple_axis_state_map.insert(entity, global_triple_axis_state);

SummarizedActionState {
button_state_map,
axis_state_map,
dual_axis_state_map,
triple_axis_state_map,
}
}

Expand Down Expand Up @@ -409,6 +476,6 @@ mod tests {
assert_eq!(action_diff_events.len(), 1);
let action_diff_event = action_diff_events[0];
assert_eq!(action_diff_event.owner, Some(entity));
assert_eq!(action_diff_event.action_diffs.len(), 3);
assert_eq!(action_diff_event.action_diffs.len(), 4);
}
}
31 changes: 30 additions & 1 deletion src/action_state/action_data.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! Contains types used to store the state of the actions held in an [`ActionState`](super::ActionState).

use bevy::{math::Vec2, reflect::Reflect, utils::Instant};
use bevy::{
math::{Vec2, Vec3},
reflect::Reflect,
utils::Instant,
};
use serde::{Deserialize, Serialize};

#[cfg(feature = "timing")]
Expand Down Expand Up @@ -30,6 +34,9 @@ impl ActionData {
InputControlKind::Button => ActionKindData::Button(ButtonData::default()),
InputControlKind::Axis => ActionKindData::Axis(AxisData::default()),
InputControlKind::DualAxis => ActionKindData::DualAxis(DualAxisData::default()),
InputControlKind::TripleAxis => {
ActionKindData::TripleAxis(TripleAxisData::default())
}
},
}
}
Expand All @@ -45,6 +52,7 @@ impl ActionData {
}
ActionKindData::Axis(ref mut _data) => {}
ActionKindData::DualAxis(ref mut _data) => {}
ActionKindData::TripleAxis(ref mut _data) => {}
}
}
}
Expand All @@ -58,6 +66,8 @@ pub enum ActionKindData {
Axis(AxisData),
/// The data for a dual-axis-like action.
DualAxis(DualAxisData),
/// The data for a triple-axis-like action.
TripleAxis(TripleAxisData),
}

impl ActionKindData {
Expand All @@ -77,6 +87,10 @@ impl ActionKindData {
data.fixed_update_pair = data.pair;
data.pair = data.update_pair;
}
Self::TripleAxis(data) => {
data.fixed_update_triple = data.triple;
data.triple = data.update_triple;
}
}
}

Expand All @@ -96,6 +110,10 @@ impl ActionKindData {
data.update_pair = data.pair;
data.pair = data.fixed_update_pair;
}
Self::TripleAxis(data) => {
data.update_triple = data.triple;
data.triple = data.fixed_update_triple;
}
}
}
}
Expand Down Expand Up @@ -196,3 +214,14 @@ pub struct DualAxisData {
/// The `pair` of the action in the `FixedMain` schedule
pub fixed_update_pair: Vec2,
}

/// The raw data for an [`ActionState`](super::ActionState) corresponding to a triple of virtual axes.
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, Reflect)]
pub struct TripleAxisData {
/// The XYZ coordinates of the axis
pub triple: Vec3,
/// The `triple` of the action in the `Main` schedule
pub update_triple: Vec3,
/// The `triple` of the action in the `FixedMain` schedule
pub fixed_update_triple: Vec3,
}
Loading

0 comments on commit 15a893a

Please sign in to comment.