1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#![allow(missing_docs)]
use crate::{charges::ChargeState, cooldown::CooldownState, Abilitylike};
use bevy::ecs::query::WorldQuery;
use leafwing_input_manager::action_state::ActionState;
#[derive(WorldQuery)]
#[world_query(mutable)]
pub struct AbilityState<A: Abilitylike> {
pub action_state: &'static ActionState<A>,
pub charges: &'static mut ChargeState<A>,
pub cooldowns: &'static mut CooldownState<A>,
}
impl<A: Abilitylike> AbilityStateItem<'_, A> {
#[inline]
#[must_use]
pub fn ready(&self, action: A) -> bool {
action.ready(&*self.charges, &*self.cooldowns)
}
#[inline]
pub fn ready_and_pressed(&self, action: A) -> bool {
self.action_state.pressed(action.clone()) && self.ready(action)
}
#[inline]
pub fn ready_and_just_pressed(&self, action: A) -> bool {
self.action_state.just_pressed(action.clone()) && self.ready(action)
}
#[inline]
pub fn trigger(&mut self, action: A) -> bool {
action.trigger(&mut *self.charges, &mut *self.cooldowns)
}
#[inline]
pub fn trigger_if_pressed(&mut self, action: A) -> bool {
if self.action_state.just_pressed(action.clone()) {
action.trigger(&mut *self.charges, &mut *self.cooldowns)
} else {
false
}
}
#[inline]
pub fn trigger_if_just_pressed(&mut self, action: A) -> bool {
if self.action_state.just_pressed(action.clone()) {
action.trigger(&mut *self.charges, &mut *self.cooldowns)
} else {
false
}
}
}
impl<A: Abilitylike> AbilityStateReadOnlyItem<'_, A> {
#[inline]
#[must_use]
pub fn ready(&self, action: A) -> bool {
action.ready(self.charges, self.cooldowns)
}
#[inline]
pub fn ready_and_pressed(&self, action: A) -> bool {
self.action_state.pressed(action.clone()) && self.ready(action)
}
#[inline]
pub fn ready_and_just_pressed(&self, action: A) -> bool {
self.action_state.just_pressed(action.clone()) && self.ready(action)
}
}
#[cfg(test)]
mod tests {
use crate as leafwing_abilities;
use crate::{AbilitiesBundle, AbilityState, Abilitylike};
use bevy::prelude::*;
use leafwing_input_manager::{action_state::ActionState, Actionlike};
#[derive(Actionlike, Abilitylike, Clone, Debug)]
enum TestAction {
Duck,
Cover,
}
#[test]
fn ability_state_methods_are_visible_from_query() {
fn simple_system(mut query: Query<AbilityState<TestAction>>) {
let mut ability_state = query.single_mut();
if ability_state.ready(TestAction::Duck) {
ability_state.trigger(TestAction::Duck);
}
}
let mut app = App::new();
app.add_system(simple_system);
}
#[test]
fn ability_state_fetches_abilities_bundle() {
let mut world = World::new();
world
.spawn()
.insert_bundle(AbilitiesBundle::<TestAction>::default())
.insert(ActionState::<TestAction>::default());
let mut query_state = world.query::<AbilityState<TestAction>>();
assert_eq!(query_state.iter(&world).len(), 1);
}
}