1- use bevy:: prelude:: * ;
1+ use bevy:: { prelude:: * , text :: FontSmoothing } ;
22use leafwing_input_manager:: prelude:: * ;
33use rand:: random_range;
44
55use crate :: {
6- PIXEL_PERFECT_LAYERS ,
6+ PIXEL_PERFECT_LAYERS , ScaleFactor ,
77 audio:: { PlaySfxEvent , PlaySoundtrackEvent , SoundEffect , Soundtrack } ,
88 input:: Action ,
99 screens:: Screen ,
10+ sundry:: BLACK ,
1011} ;
1112
12- // #[derive(Resource)]
13- // pub struct GameStats {
14- // pub asteroids_destroyed: u32,
15- // pub distance_traveled: u32,
16- // pub shots_fired: u32,
17- // pub shots_hit: u32,
18- // pub time_played: f32,
19- // }
13+ #[ derive( Resource ) ]
14+ pub struct GameStats {
15+ pub asteroids_destroyed : u32 ,
16+ pub distance_traveled : u32 ,
17+ pub shots_fired : u32 ,
18+ pub shots_hit : u32 ,
19+ // pub time_played: f32,
20+ // pub successful_trip: bool,
21+ }
2022
2123#[ derive( States , Copy , Clone , Eq , PartialEq , Hash , Debug , Default ) ]
2224pub enum GameState {
@@ -33,6 +35,14 @@ struct HasEntered(bool);
3335
3436pub ( super ) fn plugin ( app : & mut App ) {
3537 app. init_state :: < GameState > ( ) ;
38+ app. insert_resource ( GameStats {
39+ asteroids_destroyed : 0 ,
40+ distance_traveled : 0 ,
41+ shots_fired : 0 ,
42+ shots_hit : 0 ,
43+ // time_played: 0.0,
44+ // successful_trip: false,
45+ } ) ;
3646 app. insert_resource :: < HasEntered > ( HasEntered ( false ) ) ;
3747
3848 app. add_systems (
@@ -146,7 +156,12 @@ fn enter_player(
146156 mut player : Query < ( & mut Transform , & ShipSpeedSprites ) , With < Player > > ,
147157 mut thruster : Query < & mut Sprite , With < Thruster > > ,
148158 mut has_entered : ResMut < HasEntered > ,
159+ mut game_stats : ResMut < GameStats > ,
149160) {
161+ game_stats. asteroids_destroyed = 0 ;
162+ game_stats. distance_traveled = 0 ;
163+ game_stats. shots_fired = 0 ;
164+ game_stats. shots_hit = 0 ;
150165 let player = player. single_mut ( ) ;
151166 if player. is_err ( ) {
152167 return ;
@@ -223,6 +238,7 @@ fn player_input(
223238 mut thruster : Query < & mut Sprite , With < Thruster > > ,
224239 time : Res < Time < Virtual > > ,
225240 asset_server : Res < AssetServer > ,
241+ mut game_stats : ResMut < GameStats > ,
226242) {
227243 let action_state = input_query. single ( ) . unwrap ( ) ;
228244 let player = player_query. single_mut ( ) ;
@@ -274,6 +290,9 @@ fn player_input(
274290 }
275291
276292 if action_state. pressed ( & Action :: Shoot ) && player. can_shoot {
293+ player. can_shoot = false ;
294+ player. timer . reset ( ) ;
295+ game_stats. shots_fired += 1 ;
277296 commands. trigger ( PlaySfxEvent {
278297 sfx : SoundEffect :: Shoot ,
279298 } ) ;
@@ -291,8 +310,6 @@ fn player_input(
291310 Projectile ,
292311 DespawnOnExit ( Screen :: Game ) ,
293312 ) ) ;
294- player. can_shoot = false ;
295- player. timer . reset ( ) ;
296313 }
297314}
298315
@@ -446,15 +463,18 @@ fn projectile_asteroid_collision(
446463 projectiles : Query < ( Entity , & Transform ) , With < Projectile > > ,
447464 mut asteroids : Query < ( Entity , & Transform , & mut Asteroid ) > ,
448465 mut texture_atlases : ResMut < Assets < TextureAtlasLayout > > ,
466+ mut game_stats : ResMut < GameStats > ,
449467) {
450468 for ( projectile_entity, projectile_transform) in projectiles. iter ( ) {
451469 for ( asteroid_entity, asteroid_transform, mut asteroid) in asteroids. iter_mut ( ) {
452470 let distance = projectile_transform
453471 . translation
454472 . distance ( asteroid_transform. translation ) ;
455473 if distance < ( 16.0 / 2.0 ) + ( 30.0 / 2.0 ) {
474+ game_stats. shots_hit += 1 ;
456475 asteroid. health -= 1 ;
457476 if asteroid. health == 0 {
477+ game_stats. asteroids_destroyed += 1 ;
458478 commands. entity ( asteroid_entity) . despawn ( ) ;
459479 }
460480 commands. entity ( projectile_entity) . despawn ( ) ;
@@ -498,33 +518,128 @@ fn update_explosions(
498518 }
499519}
500520
501- fn spawn_game_over ( mut commands : Commands ) {
521+ fn spawn_game_over (
522+ mut commands : Commands ,
523+ asset_server : Res < AssetServer > ,
524+ scale_factor : Res < ScaleFactor > ,
525+ game_stats : Res < GameStats > ,
526+ ) {
527+ let scale = scale_factor. 0 ;
528+ let font_handle: Handle < Font > = asset_server. load ( "font.ttf" ) ;
529+
502530 commands. spawn ( (
503531 Name :: new ( "Game Over Screen" ) ,
504532 Transform {
505533 translation : Vec3 :: new ( 0.0 , 0.0 , 100.0 ) ,
506534 ..default ( )
507535 } ,
508- Node :: default ( ) ,
536+ Node {
537+ width : Val :: Percent ( 70.0 ) ,
538+ height : Val :: Percent ( 70.0 ) ,
539+ position_type : PositionType :: Absolute ,
540+ justify_content : JustifyContent :: Center ,
541+ margin : UiRect :: all ( Val :: Auto ) ,
542+ ..default ( )
543+ } ,
509544 DespawnOnExit ( Screen :: Game ) ,
510545 DespawnOnExit ( GameState :: GameOver ) ,
511546 PIXEL_PERFECT_LAYERS ,
512547 children ! [
513548 (
514549 Name :: new( "Game Over Text" ) ,
515- Text :: new( "Game Over" ) ,
516- Node :: default ( )
550+ Text :: new( "GAME OVER" ) ,
551+ TextFont {
552+ font_size: 16.0 * scale,
553+ font: font_handle. clone( ) ,
554+ font_smoothing: FontSmoothing :: None ,
555+
556+ ..default ( )
557+ } ,
558+ Node {
559+ position_type: PositionType :: Absolute ,
560+ top: Val :: Px ( 8.0 * scale) ,
561+ margin: UiRect {
562+ left: Val :: Auto ,
563+ right: Val :: Auto ,
564+ ..default ( )
565+ } ,
566+ ..default ( )
567+ }
568+ ) ,
569+ (
570+ Name :: new( "Stats container" ) ,
571+ Node {
572+ display: Display :: Flex ,
573+ flex_direction: FlexDirection :: Column ,
574+ ..default ( )
575+ } ,
576+ children![
577+ stats_row(
578+ "DISTANCE TRAVELED" ,
579+ & game_stats. distance_traveled. to_string( ) ,
580+ scale,
581+ font_handle. clone( ) ,
582+ ) ,
583+ stats_row(
584+ "SHOTS FIRED" ,
585+ & game_stats. shots_fired. to_string( ) ,
586+ scale,
587+ font_handle. clone( ) ,
588+ ) ,
589+ stats_row(
590+ "SHOTS HIT" ,
591+ & game_stats. shots_hit. to_string( ) ,
592+ scale,
593+ font_handle. clone( )
594+ ) ,
595+ stats_row(
596+ "ASTEROIDS DESTROYED" ,
597+ & game_stats. asteroids_destroyed. to_string( ) ,
598+ scale,
599+ font_handle. clone( ) ,
600+ ) ,
601+ ]
517602 ) ,
518603 (
519604 Name :: new( "Replay Button" ) ,
520605 Button ,
521606 Node {
522- margin : UiRect :: all ( Val :: Px ( 10.0 ) ) ,
523- padding : UiRect :: all ( Val :: Px ( 10.0 ) ) ,
607+ position_type : PositionType :: Absolute ,
608+ bottom : Val :: Px ( 32.0 * scale ) ,
524609 ..default ( )
525610 } ,
526- BackgroundColor ( Color :: BLACK ) ,
527- children![ ( Name :: new( "Replay Button Text" ) , Text :: new( "Replay" ) ) ] ,
611+ children![ (
612+ Name :: new( "Replay Button Text" ) ,
613+ Text :: new( "REPLAY" ) ,
614+ Node :: default ( ) ,
615+ TextFont {
616+ font_size: 16.0 * scale,
617+ font: font_handle. clone( ) ,
618+ font_smoothing: FontSmoothing :: None ,
619+ ..default ( )
620+ }
621+ ) ] ,
622+ ) ,
623+ (
624+ Name :: new( "Back to Menu Button" ) ,
625+ Button ,
626+ Node {
627+ position_type: PositionType :: Absolute ,
628+ bottom: Val :: Px ( 8.0 * scale) ,
629+ ..default ( )
630+ } ,
631+ children![ (
632+ Name :: new( "Back to Menu Text" ) ,
633+ Text :: new( "BACK TO MENU" ) ,
634+ Node :: default ( ) ,
635+ TextFont {
636+ font_size: 16.0 * scale,
637+ font: font_handle. clone( ) ,
638+ font_smoothing: FontSmoothing :: None ,
639+
640+ ..default ( )
641+ }
642+ ) ]
528643 )
529644 ] ,
530645 ) ) ;
@@ -567,3 +682,56 @@ fn trigger_music(mut commands: Commands) {
567682 soundtrack : Soundtrack :: BattleTheme ,
568683 } ) ;
569684}
685+
686+ fn stats_row ( stat : & str , value : & str , scale : f32 , font_handle : Handle < Font > ) -> impl Bundle {
687+ (
688+ Name :: new ( format ! ( "{stat} Stat" ) ) ,
689+ BackgroundColor ( BLACK ) ,
690+ Node {
691+ display : Display :: Flex ,
692+ justify_content : JustifyContent :: SpaceBetween ,
693+ top : Val :: Px ( 32.0 * scale) ,
694+ width : Val :: Percent ( 100.0 ) ,
695+ padding : UiRect {
696+ top : Val :: Px ( 8.0 * scale) ,
697+ ..default ( )
698+ } ,
699+ margin : UiRect {
700+ left : Val :: Px ( 32.0 * scale) ,
701+ right : Val :: Px ( 32.0 * scale) ,
702+ ..default ( )
703+ } ,
704+ ..default ( )
705+ } ,
706+ children ! [
707+ (
708+ Name :: new( format!( "{stat} Label" ) ) ,
709+ Text :: new( stat) ,
710+ TextFont {
711+ font_size: 16.0 * scale,
712+ font: font_handle. clone( ) ,
713+ font_smoothing: FontSmoothing :: None ,
714+ ..default ( )
715+ } ,
716+ Node {
717+ left: Val :: Px ( 0.0 ) ,
718+ ..default ( )
719+ } ,
720+ ) ,
721+ (
722+ Name :: new( format!( "{stat} Value" ) ) ,
723+ Text :: new( value) ,
724+ TextFont {
725+ font_size: 16.0 * scale,
726+ font: font_handle. clone( ) ,
727+ font_smoothing: FontSmoothing :: None ,
728+ ..default ( )
729+ } ,
730+ Node {
731+ right: Val :: Px ( 0.0 ) ,
732+ ..default ( )
733+ }
734+ )
735+ ] ,
736+ )
737+ }
0 commit comments