Skip to content

Commit cd5cc93

Browse files
committed
added victory and defeat screens
1 parent 8bdc26f commit cd5cc93

File tree

4 files changed

+329
-3
lines changed

4 files changed

+329
-3
lines changed

src/screen/playing.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
pub mod defeat_menu;
12
pub mod hud;
23
pub mod level_up_menu;
34
pub mod pause_menu;
5+
pub mod victory_menu;
46

57
use bevy::prelude::*;
68
use bevy_asset_loader::prelude::*;
@@ -20,19 +22,25 @@ use crate::game::wave::wave;
2022
use crate::game::GameRoot;
2123
use crate::screen::fade_in;
2224
use crate::screen::playing::hud::playing_hud;
25+
use crate::screen::playing::victory_menu::reset_endless_mode;
2326
use crate::screen::Screen;
2427
use crate::ui::prelude::*;
2528
use crate::util::prelude::*;
2629

2730
pub(super) fn plugin(app: &mut App) {
2831
app.add_systems(
2932
StateFlush,
30-
Screen::Playing.on_edge(stop_music, (enter_playing, start_music)),
33+
Screen::Playing.on_edge(stop_music, (enter_playing, start_music, reset_endless_mode)),
3134
);
3235

3336
app.configure::<(PlayingAssets, PlayingAction, PlayingMenu)>();
3437

35-
app.add_plugins((level_up_menu::plugin, pause_menu::plugin));
38+
app.add_plugins((
39+
level_up_menu::plugin,
40+
pause_menu::plugin,
41+
victory_menu::plugin,
42+
defeat_menu::plugin,
43+
));
3644
}
3745

3846
fn enter_playing(mut commands: Commands, game_root: Res<GameRoot>, ui_root: Res<UiRoot>) {
@@ -138,6 +146,8 @@ impl Configure for PlayingAction {
138146
enum PlayingMenu {
139147
Pause,
140148
LevelUp,
149+
Victory,
150+
Defeat,
141151
}
142152

143153
impl Configure for PlayingMenu {

src/screen/playing/defeat_menu.rs

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
use bevy::prelude::*;
2+
use bevy_kira_audio::prelude::*;
3+
use bevy_mod_picking::prelude::*;
4+
use pyri_state::extra::entity_scope::StateScope;
5+
use pyri_state::prelude::*;
6+
7+
use crate::core::pause::Pause;
8+
use crate::core::UpdateSet;
9+
use crate::game::actor::player::IsPlayer;
10+
use crate::screen::fade_out;
11+
use crate::screen::playing::PlayingAssets;
12+
use crate::screen::playing::PlayingMenu;
13+
use crate::screen::Screen;
14+
use crate::ui::prelude::*;
15+
use crate::util::prelude::*;
16+
17+
pub(super) fn plugin(app: &mut App) {
18+
app.add_systems(
19+
StateFlush,
20+
PlayingMenu::Defeat.on_edge(Pause::disable, (Pause::enable_default, open_defeat_menu)),
21+
);
22+
23+
app.add_systems(
24+
Update,
25+
PlayingMenu::Defeat
26+
.enter()
27+
.in_set(UpdateSet::SyncLate)
28+
.run_if(detect_defeat),
29+
);
30+
}
31+
32+
fn open_defeat_menu(mut commands: Commands, ui_root: Res<UiRoot>) {
33+
commands.spawn_with(defeat_overlay).set_parent(ui_root.body);
34+
commands.spawn_with(defeat_menu).set_parent(ui_root.body);
35+
}
36+
37+
pub fn detect_defeat(player_query: Query<Entity, With<IsPlayer>>) -> bool {
38+
player_query.is_empty()
39+
}
40+
41+
fn defeat_overlay(mut entity: EntityWorldMut) {
42+
entity.add(widget::blocking_overlay).insert((
43+
Name::new("DefeatOverlay"),
44+
ZIndex::Global(1),
45+
ThemeColor::Overlay.target::<BackgroundColor>(),
46+
StateScope::<PlayingMenu>::default(),
47+
));
48+
}
49+
50+
fn defeat_menu(mut entity: EntityWorldMut) {
51+
entity
52+
.insert((
53+
Name::new("DefeatMenu"),
54+
NodeBundle {
55+
style: Style::ABS_COLUMN_MID,
56+
z_index: ZIndex::Global(2),
57+
..default()
58+
},
59+
StateScope::<PlayingMenu>::default(),
60+
))
61+
.with_children(|children| {
62+
children.spawn_with(header);
63+
children.spawn_with(button_container);
64+
});
65+
}
66+
67+
const HEADER: &str = "Defeat :(";
68+
69+
fn header(mut entity: EntityWorldMut) {
70+
entity.insert((
71+
Name::new("Header"),
72+
TextBundle::from_section(
73+
HEADER,
74+
TextStyle {
75+
font: BOLD_FONT_HANDLE,
76+
..default()
77+
},
78+
)
79+
.with_style(Style {
80+
margin: UiRect::top(Vw(4.5)),
81+
..default()
82+
}),
83+
DynamicFontSize::new(Vw(5.0)).with_step(8.0),
84+
ThemeColorForText(vec![ThemeColor::BodyText]),
85+
));
86+
}
87+
88+
fn button_container(mut entity: EntityWorldMut) {
89+
entity
90+
.insert((
91+
Name::new("ButtonContainer"),
92+
NodeBundle {
93+
style: Style {
94+
align_items: AlignItems::Center,
95+
flex_direction: FlexDirection::Column,
96+
margin: UiRect::top(VMin(6.0)),
97+
row_gap: Vw(2.5),
98+
..default()
99+
},
100+
..default()
101+
},
102+
))
103+
.with_children(|children| {
104+
children.spawn_with(restart_button);
105+
children.spawn_with(quit_to_title_button);
106+
});
107+
}
108+
109+
fn restart_button(mut entity: EntityWorldMut) {
110+
entity.add(widget::menu_button("Restart")).insert((
111+
On::<Pointer<Click>>::run(
112+
|mut commands: Commands, audio: Res<Audio>, assets: Res<PlayingAssets>| {
113+
audio.play(assets.sfx_restart.clone()).with_volume(0.7);
114+
commands.spawn_with(fade_out(Screen::Playing));
115+
},
116+
),
117+
Style {
118+
height: Vw(9.0),
119+
width: Vw(38.0),
120+
align_items: AlignItems::Center,
121+
justify_content: JustifyContent::Center,
122+
..default()
123+
},
124+
));
125+
}
126+
127+
fn quit_to_title_button(mut entity: EntityWorldMut) {
128+
entity.add(widget::menu_button("Quit to title")).insert((
129+
On::<Pointer<Click>>::run(Screen::Title.enter()),
130+
Style {
131+
height: Vw(9.0),
132+
width: Vw(38.0),
133+
align_items: AlignItems::Center,
134+
justify_content: JustifyContent::Center,
135+
..default()
136+
},
137+
));
138+
}

src/screen/playing/level_up_menu.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::game::card::card;
1616
use crate::game::card::deck::Deck;
1717
use crate::game::card::deck::IsDeckDisplay;
1818
use crate::game::card::CardConfig;
19+
use crate::screen::playing::victory_menu::detect_victory;
1920
use crate::screen::playing::PlayingAssets;
2021
use crate::screen::playing::PlayingMenu;
2122
use crate::ui::prelude::*;
@@ -32,7 +33,7 @@ pub(super) fn plugin(app: &mut App) {
3233
PlayingMenu::LevelUp
3334
.enter()
3435
.in_set(UpdateSet::SyncLate)
35-
.run_if(on_event::<LevelUp>()),
36+
.run_if(on_event::<LevelUp>().and_then(not(detect_victory))),
3637
);
3738

3839
app.configure::<(LevelUpMenuAction, ToggleDisplay)>();

src/screen/playing/victory_menu.rs

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
use bevy::prelude::*;
2+
use bevy_kira_audio::prelude::*;
3+
use bevy_mod_picking::prelude::*;
4+
use pyri_state::extra::entity_scope::StateScope;
5+
use pyri_state::prelude::*;
6+
7+
use crate::core::pause::Pause;
8+
use crate::core::UpdateSet;
9+
use crate::game::actor::level::up::LevelUp;
10+
use crate::game::actor::level::Level;
11+
use crate::screen::fade_out;
12+
use crate::screen::playing::PlayingAssets;
13+
use crate::screen::playing::PlayingMenu;
14+
use crate::screen::Screen;
15+
use crate::ui::prelude::*;
16+
use crate::util::prelude::*;
17+
18+
pub(super) fn plugin(app: &mut App) {
19+
app.add_systems(
20+
StateFlush,
21+
PlayingMenu::Victory.on_edge(Pause::disable, (Pause::enable_default, open_victory_menu)),
22+
);
23+
24+
app.init_resource::<EndlessMode>();
25+
26+
app.add_systems(
27+
Update,
28+
PlayingMenu::Victory
29+
.enter()
30+
.in_set(UpdateSet::SyncLate)
31+
.run_if(on_event::<LevelUp>().and_then(detect_victory)),
32+
);
33+
}
34+
35+
#[derive(Default, Resource)]
36+
pub struct EndlessMode(bool);
37+
38+
fn open_victory_menu(mut commands: Commands, ui_root: Res<UiRoot>) {
39+
commands
40+
.spawn_with(victory_overlay)
41+
.set_parent(ui_root.body);
42+
commands.spawn_with(victory_menu).set_parent(ui_root.body);
43+
}
44+
45+
pub fn detect_victory(level_query: Query<&Level>, endless_mode: Res<EndlessMode>) -> bool {
46+
if endless_mode.0 {
47+
return false;
48+
}
49+
50+
if let Some(level) = level_query.iter().last() {
51+
return level.current >= 10;
52+
}
53+
54+
false
55+
}
56+
57+
fn victory_overlay(mut entity: EntityWorldMut) {
58+
entity.add(widget::blocking_overlay).insert((
59+
Name::new("VictoryOverlay"),
60+
ZIndex::Global(1),
61+
ThemeColor::Overlay.target::<BackgroundColor>(),
62+
StateScope::<PlayingMenu>::default(),
63+
));
64+
}
65+
66+
fn victory_menu(mut entity: EntityWorldMut) {
67+
entity
68+
.insert((
69+
Name::new("VictoryMenu"),
70+
NodeBundle {
71+
style: Style::ABS_COLUMN_MID,
72+
z_index: ZIndex::Global(2),
73+
..default()
74+
},
75+
StateScope::<PlayingMenu>::default(),
76+
))
77+
.with_children(|children| {
78+
children.spawn_with(header);
79+
children.spawn_with(button_container);
80+
});
81+
}
82+
83+
const HEADER: &str = "Victory :)";
84+
85+
fn header(mut entity: EntityWorldMut) {
86+
entity.insert((
87+
Name::new("Header"),
88+
TextBundle::from_section(
89+
HEADER,
90+
TextStyle {
91+
font: BOLD_FONT_HANDLE,
92+
..default()
93+
},
94+
)
95+
.with_style(Style {
96+
margin: UiRect::top(Vw(4.5)),
97+
..default()
98+
}),
99+
DynamicFontSize::new(Vw(5.0)).with_step(8.0),
100+
ThemeColorForText(vec![ThemeColor::BodyText]),
101+
));
102+
}
103+
104+
fn button_container(mut entity: EntityWorldMut) {
105+
entity
106+
.insert((
107+
Name::new("ButtonContainer"),
108+
NodeBundle {
109+
style: Style {
110+
align_items: AlignItems::Center,
111+
flex_direction: FlexDirection::Column,
112+
margin: UiRect::top(VMin(6.0)),
113+
row_gap: Vw(2.5),
114+
..default()
115+
},
116+
..default()
117+
},
118+
))
119+
.with_children(|children| {
120+
children.spawn_with(keep_playing_button);
121+
children.spawn_with(restart_button);
122+
children.spawn_with(quit_to_title_button);
123+
});
124+
}
125+
126+
pub fn reset_endless_mode(mut endless_mode: ResMut<EndlessMode>) {
127+
endless_mode.0 = false;
128+
}
129+
130+
fn keep_playing_button(mut entity: EntityWorldMut) {
131+
entity.add(widget::menu_button("Keep Playing")).insert((
132+
On::<Pointer<Click>>::run(
133+
|mut endless_mode: ResMut<EndlessMode>, mut playing_menu: NextMut<PlayingMenu>| {
134+
endless_mode.0 = true;
135+
playing_menu.disable();
136+
},
137+
),
138+
Style {
139+
height: Vw(9.0),
140+
width: Vw(38.0),
141+
align_items: AlignItems::Center,
142+
justify_content: JustifyContent::Center,
143+
..default()
144+
},
145+
));
146+
}
147+
148+
fn restart_button(mut entity: EntityWorldMut) {
149+
entity.add(widget::menu_button("Restart")).insert((
150+
On::<Pointer<Click>>::run(
151+
|mut commands: Commands, audio: Res<Audio>, assets: Res<PlayingAssets>| {
152+
audio.play(assets.sfx_restart.clone()).with_volume(0.7);
153+
commands.spawn_with(fade_out(Screen::Playing));
154+
},
155+
),
156+
Style {
157+
height: Vw(9.0),
158+
width: Vw(38.0),
159+
align_items: AlignItems::Center,
160+
justify_content: JustifyContent::Center,
161+
..default()
162+
},
163+
));
164+
}
165+
166+
fn quit_to_title_button(mut entity: EntityWorldMut) {
167+
entity.add(widget::menu_button("Quit to title")).insert((
168+
On::<Pointer<Click>>::run(Screen::Title.enter()),
169+
Style {
170+
height: Vw(9.0),
171+
width: Vw(38.0),
172+
align_items: AlignItems::Center,
173+
justify_content: JustifyContent::Center,
174+
..default()
175+
},
176+
));
177+
}

0 commit comments

Comments
 (0)