diff --git a/game/src/scenes/fsm_error_screen.rs b/game/src/scenes/fsm_error_screen.rs index d1fee04..2390f42 100644 --- a/game/src/scenes/fsm_error_screen.rs +++ b/game/src/scenes/fsm_error_screen.rs @@ -61,7 +61,7 @@ impl Action for FsmErrorScreen { } impl ScreenSpaceRender for FsmErrorScreen { - fn render_screen_space(&self, raylib: &mut HackedRaylibHandle, config: &GameConfig) { + fn render_screen_space(&mut self, raylib: &mut HackedRaylibHandle, config: &GameConfig) { raylib.clear_background(Color::RED); // Render a warning message diff --git a/game/src/scenes/how_to_play_screen.rs b/game/src/scenes/how_to_play_screen.rs new file mode 100644 index 0000000..1537345 --- /dev/null +++ b/game/src/scenes/how_to_play_screen.rs @@ -0,0 +1,170 @@ +use std::ops::{Div, Sub}; + +use chrono::{DateTime, Utc}; +use dirty_fsm::{Action, ActionFlag}; +use pkg_version::pkg_version_major; +use raylib::prelude::*; + +use crate::{GameConfig, context::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, info, trace}; + +#[derive(Debug)] +pub struct HowToPlayScreen { + is_btm_pressed: bool //Is back to menu button pressed +} + +impl HowToPlayScreen { + /// Construct a new `HowToPlayScreen` + pub fn new() -> Self { + Self { + is_btm_pressed: false + } + } +} + +impl Action for HowToPlayScreen { + fn on_register(&mut self) -> Result<(), ScreenError> { + debug!("Registered"); + Ok(()) + } + + fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + debug!("Running HowToPlayScreen for the first time"); + + Ok(()) + } + + fn execute( + &mut self, + _delta: &chrono::Duration, + context: &GameContext, + ) -> Result, ScreenError> { + trace!("execute() called on HowToPlayScreen"); + self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config); + + if self.is_btm_pressed { + Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen)) + } + else{ + Ok(ActionFlag::Continue) + } + } + + fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> { + debug!("Finished HowToPlayScreen"); + self.is_btm_pressed = false; + Ok(()) + } +} + +impl ScreenSpaceRender for HowToPlayScreen { + fn render_screen_space( + &mut self, + raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, + config: &GameConfig + ) { + + // Render the background + raylib.clear_background(Color::BLACK); + + 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); + + raylib.draw_text( + + "How to Play", + 37, + 80, + 70, + Color::BLUE, + ); + + raylib.draw_text( + + "How to Play", + 43, + 80, + 70, + Color::RED, + ); + + raylib.draw_text( + + "How to Play", + 40, + 80, + 70, + Color::WHITE, + ); + + //Back to Menu + if Rectangle::new(35.0, screen_size.y as f32 - 80.0, 200.0, 40.0).check_collision_point_rec(mouse_position){ + raylib.draw_text( + + "BACK TO MENU", + 28, + screen_size.y as i32 - 50, + 25, + Color::RED, + ); + raylib.draw_text( + + "BACK TO MENU", + 22, + screen_size.y as i32 - 50, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "BACK TO MENU", + 25, + screen_size.y as i32 - 50, + 25, + Color::WHITE, + ); + + if mouse_pressed{ + self.is_btm_pressed = true; + } + } + else { + raylib.draw_text( + + "BACK TO MENU", + 26, + screen_size.y as i32 - 50, + 25, + Color::RED, + ); + raylib.draw_text( + + "BACK TO MENU", + 24, + screen_size.y as i32 - 50, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "BACK TO MENU", + 25, + screen_size.y as i32 - 50, + 25, + Color::WHITE, + ); + } + } +} diff --git a/game/src/scenes/ingame_scene/hud.rs b/game/src/scenes/ingame_scene/hud.rs index 44d3b3f..bdcd6bd 100644 --- a/game/src/scenes/ingame_scene/hud.rs +++ b/game/src/scenes/ingame_scene/hud.rs @@ -4,7 +4,7 @@ use super::InGameScreen; impl ScreenSpaceRender for InGameScreen { fn render_screen_space( - &self, + &mut self, raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, config: &GameConfig ) { diff --git a/game/src/scenes/ingame_scene/world.rs b/game/src/scenes/ingame_scene/world.rs index 817c4ca..ea1a30e 100644 --- a/game/src/scenes/ingame_scene/world.rs +++ b/game/src/scenes/ingame_scene/world.rs @@ -12,7 +12,7 @@ pub const WORLD_LEVEL_X_OFFSET: f32 = 200.0; impl WorldSpaceRender for InGameScreen { fn render_world_space( - &self, + &mut self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>, config: &GameConfig, ) { diff --git a/game/src/scenes/loading_screen.rs b/game/src/scenes/loading_screen.rs index 01b31be..62d6e7c 100644 --- a/game/src/scenes/loading_screen.rs +++ b/game/src/scenes/loading_screen.rs @@ -112,7 +112,7 @@ impl Action for LoadingScreen { impl ScreenSpaceRender for LoadingScreen { fn render_screen_space( - &self, + &mut self, raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, config: &GameConfig ) { diff --git a/game/src/scenes/main_menu_screen.rs b/game/src/scenes/main_menu_screen.rs index 13c8295..a6ddc18 100644 --- a/game/src/scenes/main_menu_screen.rs +++ b/game/src/scenes/main_menu_screen.rs @@ -22,12 +22,22 @@ use super::{Scenes, ScreenError}; use tracing::{debug, error, info, trace}; #[derive(Debug)] -pub struct MainMenuScreen {} +pub struct MainMenuScreen { + + is_start_pressed: bool, //Is start button pressed + is_htp_pressed: bool, //Is how to play button pressed + is_options_pressed: bool //Is options button pressed + +} impl MainMenuScreen { /// Construct a new `MainMenuScreen` pub fn new() -> Self { - Self {} + Self { + is_start_pressed: false, + is_htp_pressed: false, + is_options_pressed: false + } } } @@ -60,27 +70,32 @@ impl Action for MainMenuScreen { trace!("execute() called on MainMenuScreen"); self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config); - // TODO: TEMP - if context - .renderer - .borrow_mut() - .is_key_pressed(KeyboardKey::KEY_SPACE) - { + if self.is_start_pressed { Ok(ActionFlag::SwitchState(Scenes::InGameScene)) - } else { + } + else if self.is_htp_pressed { + Ok(ActionFlag::SwitchState(Scenes::HowToPlayScreen)) + } + else if self.is_options_pressed { + Ok(ActionFlag::SwitchState(Scenes::OptionsScreen)) + } + else { Ok(ActionFlag::Continue) } } fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> { debug!("Finished MainMenuScreen"); + self.is_start_pressed = false; + self.is_htp_pressed = false; + self.is_options_pressed = false; Ok(()) } } impl ScreenSpaceRender for MainMenuScreen { fn render_screen_space( - &self, + &mut self, raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, config: &GameConfig, ) { @@ -90,6 +105,11 @@ impl ScreenSpaceRender for MainMenuScreen { // Calculate the logo position 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); + // Only in debug mode, render a debug message #[cfg(debug_assertions)] { @@ -101,6 +121,16 @@ impl ScreenSpaceRender for MainMenuScreen { Color::WHITE, ); } + + // Displays mouse position + raylib.draw_text( + &format!("[{}, {}]", mouse_position.x, mouse_position.y), + screen_size.x as i32 - 130, + screen_size.y as i32 - 30, + 25, + Color::DARKGRAY, + ); + // Render the game version info raylib.draw_text( &format!( @@ -113,5 +143,207 @@ impl ScreenSpaceRender for MainMenuScreen { 15, Color::WHITE, ); + + raylib.draw_text( + + &format!("[{}]", config.name), + 37, + 80, + 70, + Color::BLUE, + ); + + raylib.draw_text( + + &format!("[{}]", config.name), + 43, + 80, + 70, + Color::RED, + ); + + raylib.draw_text( + + &format!("[{}]", config.name), + 40, + 80, + 70, + Color::WHITE, + ); + + // Start Game + if Rectangle::new(80.0, 300.0, 170.0, 20.0).check_collision_point_rec(mouse_position) { + raylib.draw_text( + + "START GAME", + 83, + 300, + 25, + Color::RED, + ); + raylib.draw_text( + + "START GAME", + 77, + 300, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "START GAME", + 80, + 300, + 25, + Color::WHITE, + ); + + if mouse_pressed{ + self.is_start_pressed = true; + } + } + else{ + raylib.draw_text( + + "START GAME", + 81, + 300, + 25, + Color::RED, + ); + raylib.draw_text( + + "START GAME", + 79, + 300, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "START GAME", + 80, + 300, + 25, + Color::WHITE, + ); + } + + // How to Play + if Rectangle::new(80.0, 350.0, 170.0, 20.0).check_collision_point_rec(mouse_position) { + raylib.draw_text( + + "HOW TO PLAY", + 83, + 350, + 25, + Color::RED, + ); + raylib.draw_text( + + "HOW TO PLAY", + 77, + 350, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "HOW TO PLAY", + 80, + 350, + 25, + Color::WHITE, + ); + + if mouse_pressed{ + self.is_htp_pressed = true; + } + } + else{ + raylib.draw_text( + + "HOW TO PLAY", + 81, + 350, + 25, + Color::RED, + ); + raylib.draw_text( + + "HOW TO PLAY", + 79, + 350, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "HOW TO PLAY", + 80, + 350, + 25, + Color::WHITE, + ); + } + + // OPTIONS + if Rectangle::new(80.0, 400.0, 135.0, 20.0).check_collision_point_rec(mouse_position) { + raylib.draw_text( + + "OPTIONS", + 83, + 400, + 25, + Color::RED, + ); + raylib.draw_text( + + "OPTIONS", + 77, + 400, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "OPTIONS", + 80, + 400, + 25, + Color::WHITE, + ); + + if mouse_pressed{ + self.is_options_pressed = true; + } + + } + else{ + raylib.draw_text( + + "OPTIONS", + 81, + 400, + 25, + Color::RED, + ); + raylib.draw_text( + + "OPTIONS", + 79, + 400, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "OPTIONS", + 80, + 400, + 25, + Color::WHITE, + ); + } } } diff --git a/game/src/scenes/mod.rs b/game/src/scenes/mod.rs index a3afe32..3221362 100644 --- a/game/src/scenes/mod.rs +++ b/game/src/scenes/mod.rs @@ -3,7 +3,7 @@ use self::{ fsm_error_screen::FsmErrorScreen, ingame_scene::{level::loader::load_all_levels, InGameScreen}, loading_screen::LoadingScreen, - main_menu_screen::MainMenuScreen, + main_menu_screen::MainMenuScreen, options_screen::OptionsScreen, how_to_play_screen::HowToPlayScreen, }; use crate::{ context::GameContext, @@ -19,9 +19,10 @@ pub mod fsm_error_screen; pub mod ingame_scene; pub mod loading_screen; pub mod main_menu_screen; +pub mod how_to_play_screen; +pub mod options_screen; pub mod pause_screen; - /// Defines all scenes #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)] pub enum Scenes { @@ -30,6 +31,8 @@ pub enum Scenes { LoadingScreen, MainMenuScreen, InGameScene, + HowToPlayScreen, + OptionsScreen, PauseScreen, } @@ -64,10 +67,13 @@ pub fn build_screen_state_machine( LoadingScreen::new(raylib_handle, thread)?, )?; machine.add_action(Scenes::MainMenuScreen, MainMenuScreen::new())?; + machine.add_action(Scenes::HowToPlayScreen, HowToPlayScreen::new())?; + machine.add_action(Scenes::OptionsScreen, OptionsScreen::new())?; machine.add_action(Scenes::PauseScreen, PauseScreen::new())?; machine.add_action( Scenes::InGameScene, InGameScreen::new(player_sprite_sheet, world_background, levels), )?; Ok(machine) + } diff --git a/game/src/scenes/options_screen.rs b/game/src/scenes/options_screen.rs new file mode 100644 index 0000000..bf51602 --- /dev/null +++ b/game/src/scenes/options_screen.rs @@ -0,0 +1,171 @@ +use std::ops::{Div, Sub}; + +use chrono::{DateTime, Utc}; +use dirty_fsm::{Action, ActionFlag}; +use pkg_version::pkg_version_major; +use raylib::prelude::*; + +use crate::{GameConfig, context::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, info, trace}; + +#[derive(Debug)] +pub struct OptionsScreen { + is_btm_pressed: bool //Is back to menu button pressed +} + +impl OptionsScreen { + /// Construct a new `OptionsScreen` + pub fn new() -> Self { + Self { + is_btm_pressed: false + } + } +} + +impl Action for OptionsScreen { + fn on_register(&mut self) -> Result<(), ScreenError> { + debug!("Registered"); + Ok(()) + } + + fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> { + debug!("Running OptionsScreen for the first time"); + + Ok(()) + } + + fn execute( + &mut self, + _delta: &chrono::Duration, + context: &GameContext, + ) -> Result, ScreenError> { + trace!("execute() called on OptionsScreen"); + self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config); + + if self.is_btm_pressed { + Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen)) + } + else{ + Ok(ActionFlag::Continue) + } + } + + fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> { + debug!("Finished OptionsScreen"); + self.is_btm_pressed = false; + Ok(()) + } +} + +impl ScreenSpaceRender for OptionsScreen { + fn render_screen_space( + &mut self, + raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, + config: &GameConfig + ) { + + // Render the background + raylib.clear_background(Color::BLACK); + + 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); + + raylib.draw_text( + + "Options", + 37, + 80, + 70, + Color::BLUE, + ); + + raylib.draw_text( + + "Options", + 43, + 80, + 70, + Color::RED, + ); + + raylib.draw_text( + + "Options", + 40, + 80, + 70, + Color::WHITE, + ); + + //Back to Menu + if Rectangle::new(35.0, screen_size.y as f32 - 80.0, 200.0, 40.0).check_collision_point_rec(mouse_position){ + raylib.draw_text( + + "BACK TO MENU", + 28, + screen_size.y as i32 - 50, + 25, + Color::RED, + ); + raylib.draw_text( + + "BACK TO MENU", + 22, + screen_size.y as i32 - 50, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "BACK TO MENU", + 25, + screen_size.y as i32 - 50, + 25, + Color::WHITE, + ); + + if mouse_pressed{ + self.is_btm_pressed = true; + + } + } + else { + raylib.draw_text( + + "BACK TO MENU", + 26, + screen_size.y as i32 - 50, + 25, + Color::RED, + ); + raylib.draw_text( + + "BACK TO MENU", + 24, + screen_size.y as i32 - 50, + 25, + Color::BLUE, + ); + raylib.draw_text( + + "BACK TO MENU", + 25, + screen_size.y as i32 - 50, + 25, + Color::WHITE, + ); + } + } +} diff --git a/game/src/scenes/pause_screen.rs b/game/src/scenes/pause_screen.rs index a496c5a..04c0bac 100644 --- a/game/src/scenes/pause_screen.rs +++ b/game/src/scenes/pause_screen.rs @@ -100,7 +100,7 @@ impl Action for PauseScreen { impl ScreenSpaceRender for PauseScreen { fn render_screen_space( - &self, + &mut self, raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle, config: &GameConfig, ) { diff --git a/game/src/utilities/render_layer.rs b/game/src/utilities/render_layer.rs index 8b5710e..9de55ab 100644 --- a/game/src/utilities/render_layer.rs +++ b/game/src/utilities/render_layer.rs @@ -7,9 +7,9 @@ pub trait FrameUpdate { } pub trait ScreenSpaceRender { - fn render_screen_space(&self, raylib: &mut HackedRaylibHandle, config: &GameConfig); + fn render_screen_space(&mut self, raylib: &mut HackedRaylibHandle, config: &GameConfig); } pub trait WorldSpaceRender { - fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>, config: &GameConfig); + fn render_world_space(&mut self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>, config: &GameConfig); }