From 109b04fcb902e80159bad6ac373990c448a3d580 Mon Sep 17 00:00:00 2001
From: Luna <luna+github@sicardi.org>
Date: Sun, 3 Oct 2021 15:58:24 -0400
Subject: [PATCH 1/3] created level select screen

---
 game/src/scenes/level_select_screen.rs | 235 +++++++++++++++++++++++++
 game/src/scenes/main_menu_screen.rs    |   4 +-
 game/src/scenes/mod.rs                 |  12 +-
 3 files changed, 242 insertions(+), 9 deletions(-)
 create mode 100644 game/src/scenes/level_select_screen.rs

diff --git a/game/src/scenes/level_select_screen.rs b/game/src/scenes/level_select_screen.rs
new file mode 100644
index 0000000..2ec99c4
--- /dev/null
+++ b/game/src/scenes/level_select_screen.rs
@@ -0,0 +1,235 @@
+use std::ops::{Div, Sub};
+
+use chrono::{DateTime, Utc};
+use dirty_fsm::{Action, ActionFlag};
+use discord_sdk::activity::{ActivityBuilder, Assets};
+use pkg_version::pkg_version_major;
+use raylib::prelude::*;
+
+use crate::{GameConfig, context::{ControlFlag, GameContext}, utilities::{
+        datastore::{load_texture_from_internal_data, ResourceLoadError},
+        game_version::get_version_string,
+        math::interpolate_exp,
+        non_ref_raylib::HackedRaylibHandle,
+        render_layer::ScreenSpaceRender,
+    }};
+
+use super::{Scenes, ScreenError};
+use tracing::{debug, error, info, trace};
+
+#[derive(Debug)]
+pub struct LevelSelectScreen {
+    is_level_one_pressed: bool, //Is back to menu button pressed
+    is_btm_pressed: bool,
+}
+
+impl LevelSelectScreen {
+    /// Construct a new `LevelSelectScreen`
+    pub fn new() -> Self {
+        Self {
+            is_level_one_pressed: false,
+            is_btm_pressed: false,
+        }
+    }
+}
+
+impl Action<Scenes, ScreenError, GameContext> for LevelSelectScreen {
+    fn on_register(&mut self) -> Result<(), ScreenError> {
+        debug!("Registered");
+        Ok(())
+    }
+
+    fn on_first_run(&mut self, context: &GameContext) -> Result<(), ScreenError> {
+        debug!("Running LevelSelectScreen for the first time");
+
+        if let Err(e) = context.discord_rpc_send.send(Some(
+            ActivityBuilder::default()
+                .details("learning how to play")
+                .assets(
+                    Assets::default().large("game-logo-small", Some(context.config.name.clone())),
+                ),
+        )) {
+            error!("Failed to update discord: {}", e);
+        }
+
+        Ok(())
+    }
+
+    fn execute(
+        &mut self,
+        _delta: &chrono::Duration,
+        context: &GameContext,
+    ) -> Result<dirty_fsm::ActionFlag<Scenes>, ScreenError> {
+        trace!("execute() called on LevelSelectScreen");
+        self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
+
+        if self.is_level_one_pressed {
+            context
+                .flag_send
+                .send(Some(ControlFlag::SoundTrigger("button-press".to_string())))
+                .unwrap();
+            Ok(ActionFlag::SwitchState(Scenes::InGameScene))
+        }
+        else if self.is_btm_pressed {
+            context
+                .flag_send
+                .send(Some(ControlFlag::SoundTrigger("button-press".to_string())))
+                .unwrap();
+            Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen))
+        } else {
+            Ok(ActionFlag::Continue)
+        }
+    }
+
+    fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> {
+        debug!("Finished LevelSelectScreen");
+        self.is_level_one_pressed = false;
+        self.is_btm_pressed = false;
+        Ok(())
+    }
+}
+
+impl ScreenSpaceRender for LevelSelectScreen {
+    fn render_screen_space(
+        &mut self,
+        raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
+        config: &GameConfig,
+    ) {
+        let screen_size = raylib.get_screen_size();
+
+        // Render the background
+        raylib.clear_background(Color::BLACK);
+        raylib.draw_rectangle_lines(
+            0,
+            0,
+            screen_size.x as i32,
+            screen_size.y as i32,
+            config.colors.white,
+        );
+
+        let screen_size = raylib.get_screen_size();
+
+        //Mouse Position
+        let mouse_position: Vector2 = raylib.get_mouse_position();
+
+        let mouse_pressed: bool = raylib.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON);
+
+        //Render the title
+        raylib.draw_rgb_split_text(
+            Vector2::new(40.0, 80.0),
+            "Level Select",
+            70,
+            true,
+            Color::WHITE,
+        );
+
+        // Render the levels
+        let hovering_level_one_button = Rectangle::new(100.0, 300.0, 180.0, 20.0)
+            .check_collision_point_rec(mouse_position);
+        raylib.draw_rgb_split_text(
+            Vector2::new(100.0, 300.0),
+            "LEVEL ONE",
+            25,
+            hovering_level_one_button,
+            Color::WHITE,
+        );
+        if hovering_level_one_button {
+            raylib.draw_rgb_split_text(
+                Vector2::new(70.0, 300.0),
+                ">>",
+                25,
+                hovering_level_one_button,
+                Color::WHITE,
+            );
+        };
+        self.is_level_one_pressed = mouse_pressed && hovering_level_one_button;
+
+        let hovering_level_two_button = Rectangle::new(100.0, 350.0, 180.0, 20.0)
+            .check_collision_point_rec(mouse_position);
+        raylib.draw_rgb_split_text(
+            Vector2::new(100.0, 350.0),
+            "LEVEL TWO",
+            25,
+            hovering_level_two_button,
+            Color::WHITE,
+        );
+        if hovering_level_two_button {
+            raylib.draw_rgb_split_text(
+                Vector2::new(70.0, 350.0),
+                ">>",
+                25,
+                hovering_level_two_button,
+                Color::WHITE,
+            );
+        };
+
+        let hovering_level_three_button = Rectangle::new(100.0, 400.0, 210.0, 20.0)
+            .check_collision_point_rec(mouse_position);
+        raylib.draw_rgb_split_text(
+            Vector2::new(100.0, 400.0),
+            "LEVEL THREE",
+            25,
+            hovering_level_three_button,
+            Color::WHITE,
+        );
+        if hovering_level_three_button {
+            raylib.draw_rgb_split_text(
+                Vector2::new(70.0, 400.0),
+                ">>",
+                25,
+                hovering_level_three_button,
+                Color::WHITE,
+            );
+        };
+
+        let hovering_level_four_button = Rectangle::new(100.0, 450.0, 200.0, 20.0)
+            .check_collision_point_rec(mouse_position);
+        raylib.draw_rgb_split_text(
+            Vector2::new(100.0, 450.0),
+            "LEVEL FOUR",
+            25,
+            hovering_level_four_button,
+            Color::WHITE,
+        );
+        if hovering_level_four_button {
+            raylib.draw_rgb_split_text(
+                Vector2::new(70.0, 450.0),
+                ">>",
+                25,
+                hovering_level_four_button,
+                Color::WHITE,
+            );
+        };
+
+        let hovering_level_five_button = Rectangle::new(100.0, 500.0, 200.0, 20.0)
+            .check_collision_point_rec(mouse_position);
+        raylib.draw_rgb_split_text(
+            Vector2::new(100.0, 500.0),
+            "LEVEL FIVE",
+            25,
+            hovering_level_five_button,
+            Color::WHITE,
+        );
+        if hovering_level_five_button {
+            raylib.draw_rgb_split_text(
+                Vector2::new(70.0, 500.0),
+                ">>",
+                25,
+                hovering_level_five_button,
+                Color::WHITE,
+            );
+        };
+
+        //Back to Menu
+        let hovering_back_button = Rectangle::new(35.0, screen_size.y as f32 - 80.0, 200.0, 40.0)
+            .check_collision_point_rec(mouse_position);
+        raylib.draw_rgb_split_text(
+            Vector2::new(25.0, screen_size.y - 50.0),
+            "BACK TO MENU",
+            25,
+            hovering_back_button,
+            Color::WHITE,
+        );
+        self.is_btm_pressed = hovering_back_button && mouse_pressed;
+    }
+}
diff --git a/game/src/scenes/main_menu_screen.rs b/game/src/scenes/main_menu_screen.rs
index 389dfb9..4092405 100644
--- a/game/src/scenes/main_menu_screen.rs
+++ b/game/src/scenes/main_menu_screen.rs
@@ -83,7 +83,7 @@ impl Action<Scenes, ScreenError, GameContext> for MainMenuScreen {
                 .flag_send
                 .send(Some(ControlFlag::SoundTrigger("button-press".to_string())))
                 .unwrap();
-            Ok(ActionFlag::SwitchState(Scenes::InGameScene))
+            Ok(ActionFlag::SwitchState(Scenes::LevelSelectScreen))
         } else if self.is_htp_pressed {
             context
                 .flag_send
@@ -271,6 +271,8 @@ impl ScreenSpaceRender for MainMenuScreen {
         };
         self.is_options_pressed = mouse_pressed && hovering_options;
 
+
+
         // CREDITS
         let hovering_credits =
             Rectangle::new(80.0, 445.0, 135.0, 20.0).check_collision_point_rec(mouse_position);
diff --git a/game/src/scenes/mod.rs b/game/src/scenes/mod.rs
index 1143503..963cfb3 100644
--- a/game/src/scenes/mod.rs
+++ b/game/src/scenes/mod.rs
@@ -1,11 +1,4 @@
-use self::{
-  pause_screen::PauseScreen,
-    fsm_error_screen::FsmErrorScreen,
-    ingame_scene::{level::loader::load_all_levels, InGameScreen},
-    main_menu_screen::MainMenuScreen, options_screen::OptionsScreen, how_to_play_screen::HowToPlayScreen,
-    death_screen::DeathScreen, win_screen::WinScreen,
-    next_level_screen::NextLevelScreen
-};
+use self::{death_screen::DeathScreen, fsm_error_screen::FsmErrorScreen, how_to_play_screen::HowToPlayScreen, ingame_scene::{level::loader::load_all_levels, InGameScreen}, level_select_screen::LevelSelectScreen, main_menu_screen::MainMenuScreen, next_level_screen::NextLevelScreen, options_screen::OptionsScreen, pause_screen::PauseScreen, win_screen::WinScreen};
 use crate::{context::GameContext, utilities::{datastore::{ResourceLoadError, load_music_from_internal_data, load_sound_from_internal_data, load_texture_from_internal_data}, non_ref_raylib::HackedRaylibHandle}};
 use dirty_fsm::StateMachine;
 use raylib::{texture::Texture2D, RaylibThread};
@@ -19,6 +12,7 @@ pub mod pause_screen;
 pub mod death_screen;
 pub mod win_screen;
 pub mod next_level_screen;
+pub mod level_select_screen;
 
 /// Defines all scenes
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
@@ -33,6 +27,7 @@ pub enum Scenes {
     DeathScreen,
     WinScreen,
     NextLevelScreen,
+    LevelSelectScreen,
 }
 
 /// Contains any possible errors thrown while rendering
@@ -72,6 +67,7 @@ pub fn build_screen_state_machine(
     machine.add_action(Scenes::DeathScreen, DeathScreen::new())?;
     machine.add_action(Scenes::WinScreen, WinScreen::new())?;
     machine.add_action(Scenes::NextLevelScreen, NextLevelScreen::new())?;
+    machine.add_action(Scenes::LevelSelectScreen, LevelSelectScreen::new())?;
     Ok(machine)
 
 }

From 30e900dcfd0698d18981e832a4405ce43021ff0a Mon Sep 17 00:00:00 2001
From: Evan Pratten <ewpratten@gmail.com>
Date: Sun, 3 Oct 2021 16:14:36 -0400
Subject: [PATCH 2/3] make level select extendable

---
 game/src/context.rs                    |   9 +-
 game/src/lib.rs                        |  13 ++-
 game/src/scenes/level_select_screen.rs | 145 ++++++++-----------------
 game/src/scenes/mod.rs                 |   4 +-
 game/src/utilities/mod.rs              |   1 +
 game/src/utilities/reusable_button.rs  |  20 ++++
 6 files changed, 84 insertions(+), 108 deletions(-)
 create mode 100644 game/src/utilities/reusable_button.rs

diff --git a/game/src/context.rs b/game/src/context.rs
index 6612f52..422e72c 100644
--- a/game/src/context.rs
+++ b/game/src/context.rs
@@ -4,7 +4,11 @@ use chrono::{DateTime, Duration, Utc};
 use discord_sdk::activity::ActivityBuilder;
 use raylib::audio::Sound;
 
-use crate::{GameConfig, progress::ProgressData, utilities::{audio_player::AudioPlayer, non_ref_raylib::HackedRaylibHandle}};
+use crate::{
+    progress::ProgressData,
+    utilities::{audio_player::AudioPlayer, non_ref_raylib::HackedRaylibHandle},
+    GameConfig,
+};
 
 #[derive(Debug)]
 pub enum ControlFlag {
@@ -13,7 +17,7 @@ pub enum ControlFlag {
     UpdateLevelStart(DateTime<Utc>),
     SaveProgress,
     MaybeUpdateHighScore(usize, Duration),
-    SoundTrigger(String)
+    SoundTrigger(String),
 }
 
 #[derive(Debug)]
@@ -24,6 +28,7 @@ pub struct GameContext {
     pub config: GameConfig,
     pub player_progress: ProgressData,
     pub current_level: usize,
+    pub total_levels: usize,
     pub level_start_time: DateTime<Utc>,
     pub discord_rpc_send: Sender<Option<ActivityBuilder>>,
     pub flag_send: Sender<Option<ControlFlag>>,
diff --git a/game/src/lib.rs b/game/src/lib.rs
index b768fee..36c5d47 100644
--- a/game/src/lib.rs
+++ b/game/src/lib.rs
@@ -82,7 +82,7 @@ use crate::{
     context::GameContext,
     discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
     progress::ProgressData,
-    scenes::{build_screen_state_machine, Scenes},
+    scenes::{build_screen_state_machine, ingame_scene::level::loader::load_all_levels, Scenes},
     utilities::{
         audio_player::AudioPlayer,
         datastore::{load_music_from_internal_data, load_sound_from_internal_data},
@@ -191,6 +191,7 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
             config: game_config.clone(),
             audio: audio_system,
             sounds,
+            total_levels: 0,
             current_level: 0,
             player_progress: save_file,
             level_start_time: Utc::now(),
@@ -210,10 +211,14 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
     // Start the song
     context.audio.play_music_stream(&mut main_song);
 
+    // Load all levels
+    let levels = load_all_levels(&mut context.renderer.borrow_mut(), &raylib_thread).unwrap();
+    context.total_levels = levels.len();
+
     // Get the main state machine
     info!("Setting up the scene management state machine");
     let mut game_state_machine =
-        build_screen_state_machine(&mut context.renderer.borrow_mut(), &raylib_thread).unwrap();
+        build_screen_state_machine(&mut context.renderer.borrow_mut(), &raylib_thread, levels).unwrap();
     game_state_machine
         .force_change_state(Scenes::MainMenuScreen)
         .unwrap();
@@ -374,9 +379,7 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
                                 .maybe_write_new_time(level, &time);
                         }
                         context::ControlFlag::SoundTrigger(name) => {
-                            context.audio.play_sound(
-                                context.sounds.get(&name).unwrap(),
-                            );
+                            context.audio.play_sound(context.sounds.get(&name).unwrap());
                         }
                     }
                 }
diff --git a/game/src/scenes/level_select_screen.rs b/game/src/scenes/level_select_screen.rs
index 2ec99c4..aff4619 100644
--- a/game/src/scenes/level_select_screen.rs
+++ b/game/src/scenes/level_select_screen.rs
@@ -6,29 +6,35 @@ use discord_sdk::activity::{ActivityBuilder, Assets};
 use pkg_version::pkg_version_major;
 use raylib::prelude::*;
 
-use crate::{GameConfig, context::{ControlFlag, GameContext}, utilities::{
+use crate::{
+    context::{ControlFlag, GameContext},
+    utilities::{
         datastore::{load_texture_from_internal_data, ResourceLoadError},
         game_version::get_version_string,
         math::interpolate_exp,
         non_ref_raylib::HackedRaylibHandle,
         render_layer::ScreenSpaceRender,
-    }};
+    },
+    GameConfig,
+};
 
 use super::{Scenes, ScreenError};
 use tracing::{debug, error, info, trace};
 
 #[derive(Debug)]
 pub struct LevelSelectScreen {
-    is_level_one_pressed: bool, //Is back to menu button pressed
     is_btm_pressed: bool,
+    selected_level: Option<usize>,
+    visible_levels: usize,
 }
 
 impl LevelSelectScreen {
     /// Construct a new `LevelSelectScreen`
     pub fn new() -> Self {
         Self {
-            is_level_one_pressed: false,
             is_btm_pressed: false,
+            selected_level: None,
+            visible_levels: 0,
         }
     }
 }
@@ -52,6 +58,10 @@ impl Action<Scenes, ScreenError, GameContext> for LevelSelectScreen {
             error!("Failed to update discord: {}", e);
         }
 
+        // Calculate the number of levels to render
+        self.visible_levels =
+            (context.player_progress.level_best_times.len() + 1).min(context.total_levels);
+
         Ok(())
     }
 
@@ -63,14 +73,22 @@ impl Action<Scenes, ScreenError, GameContext> for LevelSelectScreen {
         trace!("execute() called on LevelSelectScreen");
         self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
 
-        if self.is_level_one_pressed {
+        if let Some(level) = self.selected_level {
+            // Play the sound
             context
                 .flag_send
                 .send(Some(ControlFlag::SoundTrigger("button-press".to_string())))
                 .unwrap();
+
+            // Switch the level
+            context
+                .flag_send
+                .send(Some(ControlFlag::SwitchLevel(level)))
+                .unwrap();
+
+            // Enter the game
             Ok(ActionFlag::SwitchState(Scenes::InGameScene))
-        }
-        else if self.is_btm_pressed {
+        } else if self.is_btm_pressed {
             context
                 .flag_send
                 .send(Some(ControlFlag::SoundTrigger("button-press".to_string())))
@@ -83,7 +101,7 @@ impl Action<Scenes, ScreenError, GameContext> for LevelSelectScreen {
 
     fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> {
         debug!("Finished LevelSelectScreen");
-        self.is_level_one_pressed = false;
+        self.selected_level = None;
         self.is_btm_pressed = false;
         Ok(())
     }
@@ -124,101 +142,30 @@ impl ScreenSpaceRender for LevelSelectScreen {
         );
 
         // Render the levels
-        let hovering_level_one_button = Rectangle::new(100.0, 300.0, 180.0, 20.0)
-            .check_collision_point_rec(mouse_position);
-        raylib.draw_rgb_split_text(
-            Vector2::new(100.0, 300.0),
-            "LEVEL ONE",
-            25,
-            hovering_level_one_button,
-            Color::WHITE,
-        );
-        if hovering_level_one_button {
+        for level in 0..self.visible_levels {
+            let hovering_button =
+                Rectangle::new(100.0, 300.0, 180.0, 20.0).check_collision_point_rec(mouse_position);
             raylib.draw_rgb_split_text(
-                Vector2::new(70.0, 300.0),
-                ">>",
+                Vector2::new(100.0, 300.0),
+                &format!("LEVEL {}", level),
                 25,
-                hovering_level_one_button,
+                hovering_button,
                 Color::WHITE,
             );
-        };
-        self.is_level_one_pressed = mouse_pressed && hovering_level_one_button;
-
-        let hovering_level_two_button = Rectangle::new(100.0, 350.0, 180.0, 20.0)
-            .check_collision_point_rec(mouse_position);
-        raylib.draw_rgb_split_text(
-            Vector2::new(100.0, 350.0),
-            "LEVEL TWO",
-            25,
-            hovering_level_two_button,
-            Color::WHITE,
-        );
-        if hovering_level_two_button {
-            raylib.draw_rgb_split_text(
-                Vector2::new(70.0, 350.0),
-                ">>",
-                25,
-                hovering_level_two_button,
-                Color::WHITE,
-            );
-        };
-
-        let hovering_level_three_button = Rectangle::new(100.0, 400.0, 210.0, 20.0)
-            .check_collision_point_rec(mouse_position);
-        raylib.draw_rgb_split_text(
-            Vector2::new(100.0, 400.0),
-            "LEVEL THREE",
-            25,
-            hovering_level_three_button,
-            Color::WHITE,
-        );
-        if hovering_level_three_button {
-            raylib.draw_rgb_split_text(
-                Vector2::new(70.0, 400.0),
-                ">>",
-                25,
-                hovering_level_three_button,
-                Color::WHITE,
-            );
-        };
-
-        let hovering_level_four_button = Rectangle::new(100.0, 450.0, 200.0, 20.0)
-            .check_collision_point_rec(mouse_position);
-        raylib.draw_rgb_split_text(
-            Vector2::new(100.0, 450.0),
-            "LEVEL FOUR",
-            25,
-            hovering_level_four_button,
-            Color::WHITE,
-        );
-        if hovering_level_four_button {
-            raylib.draw_rgb_split_text(
-                Vector2::new(70.0, 450.0),
-                ">>",
-                25,
-                hovering_level_four_button,
-                Color::WHITE,
-            );
-        };
-
-        let hovering_level_five_button = Rectangle::new(100.0, 500.0, 200.0, 20.0)
-            .check_collision_point_rec(mouse_position);
-        raylib.draw_rgb_split_text(
-            Vector2::new(100.0, 500.0),
-            "LEVEL FIVE",
-            25,
-            hovering_level_five_button,
-            Color::WHITE,
-        );
-        if hovering_level_five_button {
-            raylib.draw_rgb_split_text(
-                Vector2::new(70.0, 500.0),
-                ">>",
-                25,
-                hovering_level_five_button,
-                Color::WHITE,
-            );
-        };
+            if hovering_button {
+                raylib.draw_rgb_split_text(
+                    Vector2::new(70.0, 300.0),
+                    ">>",
+                    25,
+                    hovering_button,
+                    Color::WHITE,
+                );
+            };
+            if mouse_pressed && hovering_button {
+                self.selected_level = Some(level);
+                break;
+            }
+        }
 
         //Back to Menu
         let hovering_back_button = Rectangle::new(35.0, screen_size.y as f32 - 80.0, 200.0, 40.0)
diff --git a/game/src/scenes/mod.rs b/game/src/scenes/mod.rs
index 963cfb3..442fd2d 100644
--- a/game/src/scenes/mod.rs
+++ b/game/src/scenes/mod.rs
@@ -1,4 +1,4 @@
-use self::{death_screen::DeathScreen, fsm_error_screen::FsmErrorScreen, how_to_play_screen::HowToPlayScreen, ingame_scene::{level::loader::load_all_levels, InGameScreen}, level_select_screen::LevelSelectScreen, main_menu_screen::MainMenuScreen, next_level_screen::NextLevelScreen, options_screen::OptionsScreen, pause_screen::PauseScreen, win_screen::WinScreen};
+use self::{death_screen::DeathScreen, fsm_error_screen::FsmErrorScreen, how_to_play_screen::HowToPlayScreen, ingame_scene::{InGameScreen, level::{Level, loader::load_all_levels}}, level_select_screen::LevelSelectScreen, main_menu_screen::MainMenuScreen, next_level_screen::NextLevelScreen, options_screen::OptionsScreen, pause_screen::PauseScreen, win_screen::WinScreen};
 use crate::{context::GameContext, utilities::{datastore::{ResourceLoadError, load_music_from_internal_data, load_sound_from_internal_data, load_texture_from_internal_data}, non_ref_raylib::HackedRaylibHandle}};
 use dirty_fsm::StateMachine;
 use raylib::{texture::Texture2D, RaylibThread};
@@ -41,6 +41,7 @@ pub enum ScreenError {
 pub fn build_screen_state_machine(
     raylib_handle: &mut HackedRaylibHandle,
     thread: &RaylibThread,
+    levels: Vec<Level>
 ) -> Result<
     // StateMachine<Scenes, ScreenError, RefCell<(NonRefDrawHandle, Rc<RefCell<GameContext>>)>>,
     StateMachine<Scenes, ScreenError, GameContext>,
@@ -51,7 +52,6 @@ pub fn build_screen_state_machine(
         load_texture_from_internal_data(raylib_handle, thread, "character/player_run.png").unwrap();
     let world_background =
         load_texture_from_internal_data(raylib_handle, thread, "default-texture.png").unwrap();
-    let levels = load_all_levels(raylib_handle, thread).unwrap();
 
     // Set up the state machine
     let mut machine = StateMachine::new();
diff --git a/game/src/utilities/mod.rs b/game/src/utilities/mod.rs
index 666e389..a1965ea 100644
--- a/game/src/utilities/mod.rs
+++ b/game/src/utilities/mod.rs
@@ -9,3 +9,4 @@ pub mod render_layer;
 pub mod shaders;
 pub mod world_paint_texture;
 pub mod audio_player;
+pub mod reusable_button;
diff --git a/game/src/utilities/reusable_button.rs b/game/src/utilities/reusable_button.rs
new file mode 100644
index 0000000..e370d37
--- /dev/null
+++ b/game/src/utilities/reusable_button.rs
@@ -0,0 +1,20 @@
+// use raylib::prelude::*;
+
+
+// #[derive(Debug)]
+// pub struct ReusableButton {
+//     text: String,
+//     position: Vector2,
+//     font_size: f32,
+//     font_color: Color,
+//     arrow_on_hover: bool
+// }
+
+// impl ReusableButton {
+//     /// Construct a new reusable button.
+//     pub fn new() -> Self {
+//         Self {
+
+//         }
+//     }
+// }

From dae003b91640e4f93e8b82bac715a17afb04802b Mon Sep 17 00:00:00 2001
From: Evan Pratten <ewpratten@gmail.com>
Date: Sun, 3 Oct 2021 16:17:42 -0400
Subject: [PATCH 3/3] Select dem levelz

---
 game/assets/levels/levels.json         | 1 +
 game/src/scenes/level_select_screen.rs | 6 +++---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/game/assets/levels/levels.json b/game/assets/levels/levels.json
index 768078c..626517d 100644
--- a/game/assets/levels/levels.json
+++ b/game/assets/levels/levels.json
@@ -1,3 +1,4 @@
 [
+    "level_0",
     "level_1"
 ]
diff --git a/game/src/scenes/level_select_screen.rs b/game/src/scenes/level_select_screen.rs
index aff4619..029d8a3 100644
--- a/game/src/scenes/level_select_screen.rs
+++ b/game/src/scenes/level_select_screen.rs
@@ -144,9 +144,9 @@ impl ScreenSpaceRender for LevelSelectScreen {
         // Render the levels
         for level in 0..self.visible_levels {
             let hovering_button =
-                Rectangle::new(100.0, 300.0, 180.0, 20.0).check_collision_point_rec(mouse_position);
+                Rectangle::new(100.0, 300.0 + (25.0 * level as f32), 180.0, 25.0 ).check_collision_point_rec(mouse_position);
             raylib.draw_rgb_split_text(
-                Vector2::new(100.0, 300.0),
+                Vector2::new(100.0, 300.0+ (25.0 * level as f32)),
                 &format!("LEVEL {}", level),
                 25,
                 hovering_button,
@@ -154,7 +154,7 @@ impl ScreenSpaceRender for LevelSelectScreen {
             );
             if hovering_button {
                 raylib.draw_rgb_split_text(
-                    Vector2::new(70.0, 300.0),
+                    Vector2::new(70.0, 300.0+ (25.0 * level as f32)),
                     ">>",
                     25,
                     hovering_button,