Skip to content

Commit 9963750

Browse files
committed
Implement pausing
1 parent 02be65d commit 9963750

15 files changed

+214
-40
lines changed

src/animation.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,29 @@ pub mod offset;
33
pub mod transition;
44

55
use bevy::prelude::*;
6-
use bevy_tweening::TweeningPlugin;
6+
use bevy_tweening::*;
7+
use pyri_state::prelude::*;
8+
9+
use crate::core::pause::Pause;
710

811
pub(super) fn plugin(app: &mut App) {
912
app.add_plugins(TweeningPlugin);
13+
app.add_systems(
14+
StateFlush,
15+
Pause.on_edge(unpause_tweens::<Sprite>, pause_tweens::<Sprite>),
16+
);
1017

1118
app.add_plugins((backup::plugin, offset::plugin, transition::plugin));
1219
}
20+
21+
fn unpause_tweens<C: Component>(mut tween_query: Query<&mut Animator<C>>) {
22+
for mut tween in &mut tween_query {
23+
tween.state = AnimatorState::Playing;
24+
}
25+
}
26+
27+
fn pause_tweens<C: Component>(mut tween_query: Query<&mut Animator<C>>) {
28+
for mut tween in &mut tween_query {
29+
tween.state = AnimatorState::Paused;
30+
}
31+
}

src/core.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod audio;
55
pub mod camera;
66
#[cfg(feature = "dev")]
77
pub mod debug;
8+
pub mod pause;
89
pub mod physics;
910
pub mod state;
1011
pub mod theme;
@@ -38,11 +39,13 @@ pub(super) fn plugin(app: &mut App) {
3839
camera::plugin,
3940
#[cfg(feature = "dev")]
4041
debug::plugin,
41-
theme::plugin,
42+
pause::plugin,
4243
physics::plugin,
44+
theme::plugin,
4345
));
4446
}
4547

48+
// TODO: This would fit better in `game.rs`.
4649
/// Game logic system ordering in the [`Update`] schedule.
4750
#[derive(SystemSet, Clone, Eq, PartialEq, Hash, Debug)]
4851
pub enum UpdateSet {
@@ -89,6 +92,7 @@ impl Configure for UpdateSet {
8992
}
9093
}
9194

95+
// TODO: This would fit better in `animation.rs`.
9296
/// [`Transform`] post-processing system ordering in the [`PostUpdate`] schedule.
9397
#[derive(SystemSet, Clone, Eq, PartialEq, Hash, Debug)]
9498
pub enum PostTransformSet {
@@ -120,6 +124,7 @@ impl Configure for PostTransformSet {
120124
}
121125
}
122126

127+
// TODO: This would fit better in `animation.rs`.
123128
/// [`Color`] post-processing system ordering in the [`PostUpdate`] schedule.
124129
#[derive(SystemSet, Clone, Eq, PartialEq, Hash, Debug)]
125130
pub enum PostColorSet {

src/core/camera.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use bevy::core_pipeline::tonemapping::Tonemapping;
22
use bevy::prelude::*;
33
use bevy::render::camera::ScalingMode;
4+
use pyri_state::prelude::*;
45
use serde::Deserialize;
56
use serde::Serialize;
67

8+
use crate::core::pause::Pause;
79
use crate::core::UpdateSet;
810
use crate::util::prelude::*;
911

@@ -86,7 +88,7 @@ pub struct SmoothFollow {
8688
impl Configure for SmoothFollow {
8789
fn configure(app: &mut App) {
8890
app.register_type::<Self>();
89-
app.add_systems(Update, apply_smooth_follow);
91+
app.add_systems(Update, apply_smooth_follow.run_if(Pause::is_disabled));
9092
}
9193
}
9294

src/core/pause.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use bevy::prelude::*;
2+
use pyri_state::prelude::*;
3+
4+
use crate::util::prelude::*;
5+
6+
pub(super) fn plugin(app: &mut App) {
7+
app.configure::<Pause>();
8+
}
9+
10+
#[derive(State, Eq, PartialEq, Clone, Reflect, Default)]
11+
#[reflect(Resource)]
12+
pub struct Pause;
13+
14+
impl Configure for Pause {
15+
fn configure(app: &mut App) {
16+
app.register_type::<Self>();
17+
app.add_state::<Self>();
18+
}
19+
}

src/core/physics.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
use avian2d::prelude::*;
22
use bevy::prelude::*;
3+
use pyri_state::prelude::*;
4+
5+
use crate::core::pause::Pause;
36

47
pub(super) fn plugin(app: &mut App) {
58
app.add_plugins(PhysicsPlugins::default().with_length_unit(PIXELS_PER_METER));
69
app.insert_resource(Gravity::ZERO);
10+
11+
app.add_systems(StateFlush, Pause.on_edge(unpause_physics, pause_physics));
712
}
813

914
const PIXELS_PER_METER: f32 = 16.0;
15+
16+
fn pause_physics(mut physics_time: ResMut<Time<Physics>>) {
17+
physics_time.pause();
18+
}
19+
20+
fn unpause_physics(mut physics_time: ResMut<Time<Physics>>) {
21+
physics_time.unpause();
22+
}

src/game/actor/attack/input.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use bevy::prelude::*;
22
use leafwing_input_manager::prelude::*;
3+
use pyri_state::prelude::*;
34

5+
use crate::core::pause::Pause;
46
use crate::core::UpdateSet;
57
use crate::game::actor::attack::AttackController;
68
use crate::util::prelude::*;
@@ -18,7 +20,12 @@ enum AttackAction {
1820
impl Configure for AttackAction {
1921
fn configure(app: &mut App) {
2022
app.add_plugins(InputManagerPlugin::<Self>::default());
21-
app.add_systems(Update, record_attack_action.in_set(UpdateSet::RecordInput));
23+
app.add_systems(
24+
Update,
25+
record_attack_action
26+
.in_set(UpdateSet::RecordInput)
27+
.run_if(Pause::is_disabled),
28+
);
2229
}
2330
}
2431

src/game/actor/facing.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use bevy::ecs::system::EntityCommand;
22
use bevy::prelude::*;
3+
use pyri_state::prelude::*;
34

45
use crate::animation::backup::Backup;
56
use crate::core::camera::CameraRoot;
7+
use crate::core::pause::Pause;
68
use crate::core::theme::ThemeColor;
79
use crate::core::window::WindowRoot;
810
use crate::core::PostTransformSet;
@@ -47,7 +49,12 @@ pub struct FacePlayer;
4749
impl Configure for FacePlayer {
4850
fn configure(app: &mut App) {
4951
app.register_type::<Self>();
50-
app.add_systems(Update, face_player.in_set(UpdateSet::SyncEarly));
52+
app.add_systems(
53+
Update,
54+
face_player
55+
.in_set(UpdateSet::SyncEarly)
56+
.run_if(Pause::is_disabled),
57+
);
5158
}
5259
}
5360

@@ -70,7 +77,12 @@ pub struct FaceCursor;
7077
impl Configure for FaceCursor {
7178
fn configure(app: &mut App) {
7279
app.register_type::<Self>();
73-
app.add_systems(Update, face_cursor.in_set(UpdateSet::SyncEarly));
80+
app.add_systems(
81+
Update,
82+
face_cursor
83+
.in_set(UpdateSet::SyncEarly)
84+
.run_if(Pause::is_disabled),
85+
);
7486
}
7587
}
7688

src/game/actor/movement/input.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use bevy::prelude::*;
22
use leafwing_input_manager::prelude::*;
3+
use pyri_state::prelude::*;
34

5+
use crate::core::pause::Pause;
46
use crate::core::UpdateSet;
57
use crate::game::actor::movement::MovementController;
68
use crate::util::prelude::*;
@@ -19,7 +21,9 @@ impl Configure for MovementAction {
1921
app.add_plugins(InputManagerPlugin::<Self>::default());
2022
app.add_systems(
2123
Update,
22-
record_movement_action.in_set(UpdateSet::RecordInput),
24+
record_movement_action
25+
.in_set(UpdateSet::RecordInput)
26+
.run_if(Pause::is_disabled),
2327
);
2428
}
2529
}

src/game/cleanup.rs

+79-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use std::marker::PhantomData;
22

33
use bevy::prelude::*;
4+
use pyri_state::prelude::*;
45

56
use crate::core::camera::CameraRoot;
7+
use crate::core::pause::Pause;
68
use crate::core::PostTransformSet;
79
use crate::core::UpdateSet;
810
use crate::game::combat::hit::OnHit;
@@ -20,11 +22,11 @@ pub struct DespawnOnHit;
2022
impl Configure for DespawnOnHit {
2123
fn configure(app: &mut App) {
2224
app.register_type::<Self>();
23-
app.observe(despawn_on_hit);
25+
app.observe(apply_despawn_on_hit);
2426
}
2527
}
2628

27-
fn despawn_on_hit(
29+
fn apply_despawn_on_hit(
2830
trigger: Trigger<OnHit>,
2931
mut despawn: ResMut<LateDespawn>,
3032
despawn_query: Query<(), With<DespawnOnHit>>,
@@ -80,12 +82,14 @@ impl Configure for DespawnOnBeat {
8082
app.register_type::<Self>();
8183
app.add_systems(
8284
Update,
83-
despawn_on_beat.in_set(UpdateSet::Update).run_if(on_beat(1)),
85+
apply_despawn_on_beat
86+
.in_set(UpdateSet::Update)
87+
.run_if(on_beat(1)),
8488
);
8589
}
8690
}
8791

88-
fn despawn_on_beat(
92+
fn apply_despawn_on_beat(
8993
mut despawn: ResMut<LateDespawn>,
9094
mut despawn_query: Query<(Entity, &mut DespawnOnBeat)>,
9195
) {
@@ -104,17 +108,44 @@ pub struct DespawnOnTimer(pub Timer);
104108
impl Configure for DespawnOnTimer {
105109
fn configure(app: &mut App) {
106110
app.register_type::<Self>();
107-
app.add_systems(Update, despawn_on_timer.in_set(UpdateSet::Update));
111+
app.add_systems(
112+
StateFlush,
113+
Pause.on_edge(unpause_despawn_on_timer, pause_despawn_on_timer),
114+
);
115+
app.add_systems(
116+
Update,
117+
(
118+
tick_despawn_on_timer.in_set(UpdateSet::TickTimers),
119+
apply_despawn_on_timer.in_set(UpdateSet::Update),
120+
),
121+
);
108122
}
109123
}
110124

111-
fn despawn_on_timer(
112-
time: Res<Time>,
125+
fn unpause_despawn_on_timer(mut timer_query: Query<&mut DespawnOnTimer>) {
126+
for mut timer in &mut timer_query {
127+
timer.0.unpause();
128+
}
129+
}
130+
131+
fn pause_despawn_on_timer(mut timer_query: Query<&mut DespawnOnTimer>) {
132+
for mut timer in &mut timer_query {
133+
timer.0.pause();
134+
}
135+
}
136+
137+
fn tick_despawn_on_timer(time: Res<Time>, mut timer_query: Query<&mut DespawnOnTimer>) {
138+
for mut timer in &mut timer_query {
139+
timer.0.tick(time.delta());
140+
}
141+
}
142+
143+
fn apply_despawn_on_timer(
113144
mut despawn: ResMut<LateDespawn>,
114-
mut despawn_query: Query<(Entity, &mut DespawnOnTimer)>,
145+
timer_query: Query<(Entity, &DespawnOnTimer)>,
115146
) {
116-
for (entity, mut timer) in &mut despawn_query {
117-
if timer.0.tick(time.delta()).finished() {
147+
for (entity, timer) in &timer_query {
148+
if timer.0.finished() {
118149
despawn.recursive(entity);
119150
}
120151
}
@@ -131,7 +162,17 @@ pub struct RemoveOnTimer<C: Component + TypePath> {
131162
impl<C: Component + TypePath> Configure for RemoveOnTimer<C> {
132163
fn configure(app: &mut App) {
133164
app.register_type::<Self>();
134-
app.add_systems(Update, remove_on_timer::<C>.in_set(UpdateSet::SyncLate));
165+
app.add_systems(
166+
StateFlush,
167+
Pause.on_edge(unpause_remove_on_timer::<C>, pause_remove_on_timer::<C>),
168+
);
169+
app.add_systems(
170+
Update,
171+
(
172+
tick_remove_on_timer::<C>.in_set(UpdateSet::TickTimers),
173+
apply_remove_on_timer::<C>.in_set(UpdateSet::SyncLate),
174+
),
175+
);
135176
}
136177
}
137178

@@ -149,13 +190,33 @@ impl<C: Component + TypePath> RemoveOnTimer<C> {
149190
}
150191
}
151192

152-
fn remove_on_timer<C: Component + TypePath>(
153-
mut commands: Commands,
154-
mut remove_query: Query<(Entity, &mut RemoveOnTimer<C>)>,
193+
fn tick_remove_on_timer<C: Component + TypePath>(
155194
time: Res<Time>,
195+
mut timer_query: Query<&mut RemoveOnTimer<C>>,
156196
) {
157-
for (entity, mut remove) in &mut remove_query {
158-
if remove.timer.tick(time.delta()).finished() {
197+
for mut timer in &mut timer_query {
198+
timer.timer.tick(time.delta());
199+
}
200+
}
201+
202+
fn unpause_remove_on_timer<C: Component + TypePath>(mut timer_query: Query<&mut RemoveOnTimer<C>>) {
203+
for mut timer in &mut timer_query {
204+
timer.timer.unpause();
205+
}
206+
}
207+
208+
fn pause_remove_on_timer<C: Component + TypePath>(mut timer_query: Query<&mut RemoveOnTimer<C>>) {
209+
for mut timer in &mut timer_query {
210+
timer.timer.pause();
211+
}
212+
}
213+
214+
fn apply_remove_on_timer<C: Component + TypePath>(
215+
mut commands: Commands,
216+
timer_query: Query<(Entity, &RemoveOnTimer<C>)>,
217+
) {
218+
for (entity, timer) in &timer_query {
219+
if timer.timer.finished() {
159220
commands.entity(entity).remove::<(C, RemoveOnTimer<C>)>();
160221
}
161222
}
@@ -174,7 +235,7 @@ impl<C: Component + TypePath> Configure for RemoveOnBeat<C> {
174235
app.register_type::<Self>();
175236
app.add_systems(
176237
Update,
177-
remove_on_beat::<C>
238+
apply_remove_on_beat::<C>
178239
.in_set(UpdateSet::SyncLate)
179240
.run_if(on_beat(1)),
180241
);
@@ -194,7 +255,7 @@ impl<C: Component + TypePath> RemoveOnBeat<C> {
194255
}
195256
}
196257

197-
fn remove_on_beat<C: Component + TypePath>(
258+
fn apply_remove_on_beat<C: Component + TypePath>(
198259
mut commands: Commands,
199260
mut remove_query: Query<(Entity, &mut RemoveOnBeat<C>)>,
200261
) {

0 commit comments

Comments
 (0)