Skip to content

Commit 397f495

Browse files
committed
add leaderboard to home screen
1 parent d09a92b commit 397f495

File tree

7 files changed

+204
-8
lines changed

7 files changed

+204
-8
lines changed
32 KB
Loading

src/game/assets.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub enum ImageKey {
7171
StartButton,
7272
CreditsButton,
7373
SubmitButton,
74+
LeaderboardButton,
7475
}
7576

7677
impl AssetKey for ImageKey {
@@ -342,6 +343,15 @@ impl FromWorld for HandleMap<ImageKey> {
342343
},
343344
),
344345
),
346+
(
347+
ImageKey::LeaderboardButton,
348+
asset_server.load_with_settings(
349+
"images/leaderboard-button.png",
350+
|settings: &mut ImageLoaderSettings| {
351+
settings.sampler = ImageSampler::nearest();
352+
},
353+
),
354+
),
345355
]
346356
.into()
347357
}

src/screen/credits.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub(super) fn plugin(app: &mut App) {
2323

2424
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
2525
#[reflect(Component)]
26-
enum CreditsAction {
26+
pub enum CreditsAction {
2727
Back,
2828
}
2929

src/screen/leaderboard.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//! A loading screen during which game assets are loaded.
2+
//! This reduces stuttering, especially for audio on WASM.
3+
4+
use bevy::prelude::*;
5+
use bevy_http_client::prelude::{TypedRequest, TypedResponse};
6+
7+
use super::{
8+
credits::CreditsAction,
9+
playing::{get_scores, LeaderboardRecord},
10+
PlayingState, Screen,
11+
};
12+
use crate::{
13+
game::{
14+
assets::{HandleMap, ImageKey, SoundtrackKey},
15+
audio::soundtrack::PlaySoundtrack,
16+
},
17+
ui::prelude::*,
18+
};
19+
20+
pub(super) fn plugin(app: &mut App) {
21+
app.add_systems(OnEnter(Screen::Leaderboard), enter_leaderboard);
22+
app.add_systems(
23+
Update,
24+
handle_credits_action.run_if(in_state(Screen::Leaderboard)),
25+
);
26+
27+
app.add_systems(
28+
Update,
29+
handle_response.run_if(in_state(Screen::Leaderboard)),
30+
);
31+
}
32+
33+
fn enter_leaderboard(
34+
mut commands: Commands,
35+
mut ev_request: EventWriter<TypedRequest<Vec<LeaderboardRecord>>>,
36+
image_handles: Res<HandleMap<ImageKey>>,
37+
) {
38+
get_scores(ev_request);
39+
40+
commands.spawn((
41+
SpriteBundle {
42+
texture: image_handles[&ImageKey::TitleBackground].clone_weak(),
43+
transform: Transform {
44+
translation: Vec3::new(0.0, -110.0, -100.0),
45+
..default()
46+
},
47+
sprite: Sprite {
48+
custom_size: Some(Vec2::new(1280.0, 1280.0)),
49+
..default()
50+
},
51+
..default()
52+
},
53+
StateScoped(Screen::Leaderboard),
54+
));
55+
56+
commands.spawn((
57+
TextBundle {
58+
text: Text::from_section(
59+
"Leaderboard",
60+
TextStyle {
61+
font_size: 30.0,
62+
color: Color::WHITE,
63+
..default()
64+
},
65+
),
66+
style: Style {
67+
justify_self: JustifySelf::Center,
68+
margin: UiRect {
69+
top: Val::Px(50.0),
70+
..default()
71+
},
72+
..default()
73+
},
74+
..default()
75+
},
76+
StateScoped(Screen::Leaderboard),
77+
));
78+
79+
commands
80+
.ui_root()
81+
.insert(StateScoped(Screen::Leaderboard))
82+
.with_children(|children| {
83+
children
84+
.button("Back")
85+
.insert(CreditsAction::Back)
86+
.insert(Style {
87+
margin: UiRect {
88+
top: Val::Px(600.0),
89+
..default()
90+
},
91+
padding: UiRect {
92+
top: Val::Px(10.0),
93+
bottom: Val::Px(10.0),
94+
left: Val::Px(20.0),
95+
right: Val::Px(20.0),
96+
},
97+
..default()
98+
});
99+
});
100+
}
101+
102+
fn handle_credits_action(
103+
mut commands: Commands,
104+
mut next_screen: ResMut<NextState<Screen>>,
105+
mut button_query: InteractionQuery<&CreditsAction>,
106+
) {
107+
for (interaction, action) in &mut button_query {
108+
if matches!(interaction, Interaction::Pressed) {
109+
match action {
110+
CreditsAction::Back => {
111+
next_screen.set(Screen::Title);
112+
commands.trigger(PlaySoundtrack::Key(SoundtrackKey::Menu));
113+
}
114+
}
115+
}
116+
}
117+
}
118+
119+
fn handle_response(
120+
mut commands: Commands,
121+
mut ev_response: EventReader<TypedResponse<Vec<LeaderboardRecord>>>,
122+
) {
123+
for res in ev_response.read() {
124+
for (i, score) in res.iter().take(25).enumerate() {
125+
let text = format!("{}. {} - {:.2}", i + 1, score.name, score.score);
126+
commands.spawn((
127+
TextBundle {
128+
text: Text::from_section(
129+
text,
130+
TextStyle {
131+
font_size: 20.0,
132+
color: Color::WHITE,
133+
..default()
134+
},
135+
),
136+
style: Style {
137+
justify_self: JustifySelf::Center,
138+
margin: UiRect {
139+
top: Val::Px(90.0 + (i as f32 * 20.0)),
140+
..default()
141+
},
142+
..default()
143+
},
144+
..default()
145+
},
146+
StateScoped(PlayingState::GameOver),
147+
StateScoped(Screen::Leaderboard),
148+
));
149+
}
150+
}
151+
}

src/screen/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! The game's main screen states and transitions between them.
22
33
mod credits;
4+
pub mod leaderboard;
45
mod loading;
56
mod playing;
67
mod splash;
@@ -18,6 +19,7 @@ pub(super) fn plugin(app: &mut App) {
1819
title::plugin,
1920
credits::plugin,
2021
playing::plugin,
22+
leaderboard::plugin,
2123
));
2224
}
2325

@@ -30,6 +32,7 @@ pub enum Screen {
3032
Title,
3133
Credits,
3234
Playing,
35+
Leaderboard,
3336
}
3437

3538
#[derive(States, Debug, Clone, PartialEq, Eq, Hash)]

src/screen/playing.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ pub(super) fn plugin(app: &mut App) {
3939

4040
app.register_request_type::<Vec<LeaderboardRecord>>();
4141
app.register_request_type::<LeaderboardBody>();
42-
app.add_systems(Update, handle_response);
42+
app.add_systems(
43+
Update,
44+
handle_response.run_if(in_state(PlayingState::GameOver)),
45+
);
4346
}
4447

4548
fn enter_playing(mut commands: Commands, mut next_state: ResMut<NextState<PlayingState>>) {
@@ -310,10 +313,10 @@ fn game_over(
310313
}
311314

312315
#[derive(Serialize, Deserialize, Debug)]
313-
struct LeaderboardRecord {
314-
id: String,
315-
name: String,
316-
score: f32,
316+
pub struct LeaderboardRecord {
317+
pub id: String,
318+
pub name: String,
319+
pub score: f32,
317320
}
318321

319322
pub fn submit_score(
@@ -330,7 +333,7 @@ pub fn submit_score(
330333
);
331334
}
332335

333-
fn get_scores(mut ev_request: EventWriter<TypedRequest<Vec<LeaderboardRecord>>>) {
336+
pub fn get_scores(mut ev_request: EventWriter<TypedRequest<Vec<LeaderboardRecord>>>) {
334337
ev_request.send(
335338
HttpClient::new()
336339
.get("https://sr5t5qmb4c.execute-api.us-east-1.amazonaws.com/prod/leaderboard")

src/screen/title.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub enum TitleAction {
3636
Exit,
3737
Menu,
3838
SubmitScore,
39+
Leaderboard,
3940
}
4041

4142
#[derive(Component)]
@@ -151,6 +152,31 @@ fn enter_title(
151152
StateScoped(Screen::Title),
152153
));
153154

155+
commands.spawn((
156+
ButtonBundle {
157+
style: Style {
158+
width: Val::Px(213.0),
159+
height: Val::Px(63.0),
160+
justify_content: JustifyContent::Center,
161+
align_items: AlignItems::Center,
162+
align_self: AlignSelf::Center,
163+
justify_self: JustifySelf::Center,
164+
margin: UiRect {
165+
top: Val::Px(240.0),
166+
..default()
167+
},
168+
..default()
169+
},
170+
image: UiImage {
171+
texture: images[&ImageKey::LeaderboardButton].clone_weak(),
172+
..default()
173+
},
174+
..default()
175+
},
176+
TitleAction::Leaderboard,
177+
StateScoped(Screen::Title),
178+
));
179+
154180
commands.spawn((
155181
SpriteBundle {
156182
texture: images[&ImageKey::TitleBackground].clone_weak(),
@@ -167,7 +193,7 @@ fn enter_title(
167193
commands.spawn((
168194
SpriteBundle {
169195
texture: images[&ImageKey::TitleHand].clone_weak(),
170-
transform: Transform::from_translation(Vec3::new(-370.0, 0.0, 0.0)),
196+
transform: Transform::from_translation(Vec3::new(-370.0, -50.0, 0.0)),
171197
sprite: Sprite {
172198
custom_size: Some(Vec2::new(350.0, 350.0)),
173199
..default()
@@ -270,6 +296,9 @@ fn handle_title_action(
270296
}
271297
submit_score(name.0.clone().unwrap(), scoresource.0, &mut ev_request);
272298
}
299+
TitleAction::Leaderboard => {
300+
next_screen.set(Screen::Leaderboard);
301+
}
273302
}
274303
}
275304
}

0 commit comments

Comments
 (0)