diff --git a/Cargo.toml b/Cargo.toml index f53aea5..36bf495 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,9 @@ edition = "2018" description = "" [dependencies] -raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", branch = "master" } +raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", branch = "master", features = [ + "with_serde" +] } serialstudio = "0.1.0" serde = "1.0.125" serde_json = "1.0.64" @@ -14,4 +16,4 @@ failure = "0.1.8" parry2d = "0.4.0" log = "0.4.14" env_logger = "0.8.3" -nalgebra = "0.26.1" \ No newline at end of file +nalgebra = "0.26.1" diff --git a/assets/worlds/mainworld.json b/assets/worlds/mainworld.json index 544b7b4..f34b38e 100644 --- a/assets/worlds/mainworld.json +++ b/assets/worlds/mainworld.json @@ -1,3 +1,6 @@ { - + "end_position": { + "x": 10000.0, + "y": 10000.0 + } } \ No newline at end of file diff --git a/src/gamecore.rs b/src/gamecore.rs index ef7f71a..fc6b26f 100644 --- a/src/gamecore.rs +++ b/src/gamecore.rs @@ -17,7 +17,8 @@ pub enum GameState { MainMenu, PauseMenu, GameQuit, - InGame + InGame, + GameEnd } impl fmt::Display for GameState { @@ -32,6 +33,7 @@ pub struct GameCore { pub state: GameState, pub last_state: GameState, pub last_state_change_time: f64, + pub last_frame_time: f64, pub has_rendered_first_frame: bool, /// Resources @@ -56,6 +58,7 @@ impl GameCore { state: GameState::Loading, last_state: GameState::Loading, last_state_change_time: 0.0, + last_frame_time: 0.0, has_rendered_first_frame: false, resources: GlobalResources::load_all(raylib, thread) .expect("Failed to load game assets. Can not launch!"), @@ -67,7 +70,7 @@ impl GameCore { }, show_simple_debug_info: false, world: world, - player: Player::new() + player: Player::new(), } } diff --git a/src/lib/utils/profiler.rs b/src/lib/utils/profiler.rs index 37293c2..6634e5b 100644 --- a/src/lib/utils/profiler.rs +++ b/src/lib/utils/profiler.rs @@ -16,7 +16,12 @@ pub struct ProfilerData { pub active_sounds: i32, // Game core - pub game_state: String + pub game_state: String, + + // Player + pub player_coins: u32, + pub player_boost_percent: f32, + pub player_breath_percent: f32 } /// The development profiler @@ -117,6 +122,33 @@ impl GameProfiler { }, ], }, + DataGroup { + title: "Player".to_string(), + widget_type: None, + datasets: vec![ + DataSet { + title: Some("Coins".to_string()), + value: json!(self.data.player_coins), + graph: Some(false), + unit: Some("coins".to_string()), + w_type: None, + }, + DataSet { + title: Some("Breath".to_string()), + value: json!(self.data.player_boost_percent), + graph: Some(false), + unit: Some("%".to_string()), + w_type: None, + }, + DataSet { + title: Some("Breath".to_string()), + value: json!(self.data.player_breath_percent), + graph: Some(false), + unit: Some("%".to_string()), + w_type: None, + }, + ], + }, ], }; diff --git a/src/logic/gameend.rs b/src/logic/gameend.rs new file mode 100644 index 0000000..8cee91f --- /dev/null +++ b/src/logic/gameend.rs @@ -0,0 +1,126 @@ +use raylib::prelude::*; + +use crate::{ + gamecore::{GameCore, GameState}, + lib::wrappers::audio::player::AudioPlayer, +}; + +use super::screen::Screen; + +const SCREEN_PANEL_SIZE: Vector2 = Vector2 { x: 300.0, y: 300.0 }; + +pub struct GameEndScreen {} + +impl GameEndScreen { + pub fn new() -> Self { + Self {} + } +} + +impl Screen for GameEndScreen { + fn render( + &mut self, + draw_handle: &mut RaylibDrawHandle, + _thread: &RaylibThread, + audio_system: &mut AudioPlayer, + game_core: &mut GameCore, + ) -> Option { + let mouse_position = draw_handle.get_mouse_position(); + draw_handle.clear_background(Color::GRAY); + // TODO: Maybe we can stick some art here? + + + // Window dimensions + let win_height = draw_handle.get_screen_height(); + let win_width = draw_handle.get_screen_width(); + + // Render the backing to the menu itself + draw_handle.draw_rectangle( + (win_width / 2) - ((SCREEN_PANEL_SIZE.x as i32 + 6) / 2), + (win_height / 2) - ((SCREEN_PANEL_SIZE.y as i32 + 6) / 2), + SCREEN_PANEL_SIZE.x as i32 + 6, + SCREEN_PANEL_SIZE.y as i32 + 6, + Color::BLACK, + ); + draw_handle.draw_rectangle( + (win_width / 2) - (SCREEN_PANEL_SIZE.x as i32 / 2), + (win_height / 2) - (SCREEN_PANEL_SIZE.y as i32 / 2), + SCREEN_PANEL_SIZE.x as i32, + SCREEN_PANEL_SIZE.y as i32, + Color::WHITE, + ); + + // Render heading text + draw_handle.draw_text( + "OUT OF BREATH", + (win_width / 2) - 80, + (win_height / 2) - (SCREEN_PANEL_SIZE.y as i32 / 2) + 10, + 40, + Color::BLACK, + ); + + + // // Close and quit buttons + // let bottom_left_button_dimensions = Rectangle { + // x: (win_width as f32 / 2.0) - (SCREEN_PANEL_SIZE.x / 2.0) + 5.0, + // y: (win_height as f32 / 2.0) + (SCREEN_PANEL_SIZE.y / 2.0) - 50.0, + // width: (SCREEN_PANEL_SIZE.x / 2.0) - 15.0, + // height: 40.0, + // }; + // let bottom_right_button_dimensions = Rectangle { + // x: (win_width as f32 / 2.0) + 5.0, + // y: bottom_left_button_dimensions.y, + // width: bottom_left_button_dimensions.width, + // height: bottom_left_button_dimensions.height, + // }; + + // // Check if the mouse is over either button + // let mouse_over_bottom_left_button = + // bottom_left_button_dimensions.check_collision_point_rec(mouse_position); + // let mouse_over_bottom_right_button = + // bottom_right_button_dimensions.check_collision_point_rec(mouse_position); + + // // Render buttons + // draw_handle.draw_rectangle_lines_ex( + // bottom_left_button_dimensions, + // 3, + // match mouse_over_bottom_left_button { + // true => Color::GRAY, + // false => Color::BLACK, + // }, + // ); + // draw_handle.draw_text( + // "Quit", + // bottom_left_button_dimensions.x as i32 + 15, + // bottom_left_button_dimensions.y as i32 + 5, + // 30, + // Color::BLACK, + // ); + // draw_handle.draw_rectangle_lines_ex( + // bottom_right_button_dimensions, + // 3, + // match mouse_over_bottom_right_button { + // true => Color::GRAY, + // false => Color::BLACK, + // }, + // ); + // draw_handle.draw_text( + // "Close", + // bottom_right_button_dimensions.x as i32 + 15, + // bottom_right_button_dimensions.y as i32 + 5, + // 30, + // Color::BLACK, + // ); + + // // Handle click actions on the buttons + // if draw_handle.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { + // if mouse_over_bottom_left_button { + // return Some(GameState::GameQuit); + // } else if mouse_over_bottom_right_button { + // return Some(game_core.last_state); + // } + // } + + return None; + } +} diff --git a/src/logic/ingame/hud.rs b/src/logic/ingame/hud.rs new file mode 100644 index 0000000..6a70ff9 --- /dev/null +++ b/src/logic/ingame/hud.rs @@ -0,0 +1,101 @@ +use raylib::prelude::*; + +use crate::{gamecore::GameCore, pallette::TRANSLUCENT_WHITE_96}; + +pub fn render_hud( + draw_handle: &mut RaylibDrawHandle, + game_core: &mut GameCore, + window_center: Vector2, +) { + // Get the relevant data + let dist_from_player_to_end = game_core + .player + .position + .distance_to(game_core.world.end_position); + let dist_from_start_to_end = Vector2::zero().distance_to(game_core.world.end_position); + let progress = ((dist_from_start_to_end - dist_from_player_to_end) / dist_from_start_to_end) + .clamp(0.0, 1.0); + + // Determine the progress slider position + let slider_bound_height = 20.0; + let progress_slider_position = Vector2 { + x: window_center.x * 2.0, + y: (((window_center.y * 2.0) - (slider_bound_height * 2.0)) * progress) + + slider_bound_height, + }; + + // Render the base of the slider + draw_handle.draw_rectangle( + (progress_slider_position.x - slider_bound_height) as i32, + (progress_slider_position.y - slider_bound_height / 2.0) as i32, + slider_bound_height as i32, + slider_bound_height as i32, + TRANSLUCENT_WHITE_96, + ); + draw_handle.draw_triangle( + Vector2 { + x: (progress_slider_position.x - slider_bound_height), + y: (progress_slider_position.y - slider_bound_height / 2.0), + }, + Vector2 { + x: (progress_slider_position.x - slider_bound_height - (slider_bound_height / 2.0)), + y: progress_slider_position.y, + }, + Vector2 { + x: (progress_slider_position.x - slider_bound_height), + y: (progress_slider_position.y + slider_bound_height / 2.0), + }, + TRANSLUCENT_WHITE_96, + ); + + // Render the outline of the slider + draw_handle.draw_line_ex( + Vector2 { + x: (progress_slider_position.x - slider_bound_height), + y: (progress_slider_position.y - slider_bound_height / 2.0), + }, + Vector2 { + x: progress_slider_position.x, + y: (progress_slider_position.y - slider_bound_height / 2.0), + }, + 3.0, + Color::BLACK, + ); + draw_handle.draw_line_ex( + Vector2 { + x: (progress_slider_position.x - slider_bound_height), + y: (progress_slider_position.y + slider_bound_height / 2.0), + }, + Vector2 { + x: progress_slider_position.x, + y: (progress_slider_position.y + slider_bound_height / 2.0), + }, + 3.0, + Color::BLACK, + ); + draw_handle.draw_line_ex( + Vector2 { + x: (progress_slider_position.x - slider_bound_height), + y: (progress_slider_position.y - slider_bound_height / 2.0), + }, + Vector2 { + x: (progress_slider_position.x - slider_bound_height - (slider_bound_height / 2.0)), + y: progress_slider_position.y, + }, + 3.0, + Color::BLACK, + ); + draw_handle.draw_line_ex( + Vector2 { + x: (progress_slider_position.x - slider_bound_height), + y: (progress_slider_position.y + slider_bound_height / 2.0), + }, + Vector2 { + x: (progress_slider_position.x - slider_bound_height - (slider_bound_height / 2.0)), + y: progress_slider_position.y, + }, + 3.0, + Color::BLACK, + ); + +} diff --git a/src/logic/ingame/ingame.rs b/src/logic/ingame/ingame.rs deleted file mode 100644 index 40e99da..0000000 --- a/src/logic/ingame/ingame.rs +++ /dev/null @@ -1,12 +0,0 @@ - - - -pub enum ingame_states{ - BUYING, - SWIMMING, - DEAD, -} - - - - diff --git a/src/logic/ingame/mod.rs b/src/logic/ingame/mod.rs index b876de3..7297289 100644 --- a/src/logic/ingame/mod.rs +++ b/src/logic/ingame/mod.rs @@ -1,3 +1,6 @@ +mod playerlogic; +mod hud; + use raylib::prelude::*; use crate::{ @@ -7,14 +10,9 @@ use crate::{ use super::screen::Screen; -const NORMAL_PLAYER_SPEED: i32 = 4; -const BOOST_PLAYER_SPEED: i32 = NORMAL_PLAYER_SPEED * 2; -const CAMERA_FOLLOW_SPEED: f32 = 0.7; - pub enum InGameState { BUYING, SWIMMING, - DEAD, } pub struct InGameScreen { @@ -28,89 +26,15 @@ impl InGameScreen { } } - fn update_player_movement( - &mut self, - draw_handle: &mut RaylibDrawHandle, - game_core: &mut GameCore, - window_center: Vector2, - ) { - - // Handle player movement - let mouse_pose = draw_handle.get_mouse_position(); - let mouse_world_pose = draw_handle.get_screen_to_world2D(mouse_pose, game_core.master_camera); - let raw_movement_direction = mouse_world_pose - game_core.player.position; - let mut normalized_movement_direction = raw_movement_direction; - normalized_movement_direction.normalize(); - game_core.player.direction = normalized_movement_direction; - - // In the case the player is in "null", just jump the camera to them - if game_core.player.position == Vector2::zero() { - game_core.master_camera.target = game_core.player.position - (window_center / 2.0); - } - - // Handle action buttons - let user_request_boost = draw_handle.is_mouse_button_down(MouseButton::MOUSE_LEFT_BUTTON); - let user_request_action = - draw_handle.is_mouse_button_pressed(MouseButton::MOUSE_RIGHT_BUTTON); - - // Move the player in their direction - let speed_multiplier = match user_request_boost && game_core.player.boost_percent >= 0.0 { - true => BOOST_PLAYER_SPEED as f32, - false => NORMAL_PLAYER_SPEED as f32, - }; - - // Only do this if the mouse is far enough away - let player_real_movement = game_core.player.direction * speed_multiplier; - if raw_movement_direction.distance_to(Vector2::zero()) > game_core.player.size.y / 2.0 { - game_core.player.position += player_real_movement; - } - - // Move the camera to follow the player - let direction_from_cam_to_player = - (game_core.player.position - window_center) - game_core.master_camera.target; - let player_screen_position = draw_handle.get_world_to_screen2D(game_core.player.position, game_core.master_camera); - - // Camera only moves if you get close to the edge of the screen - if player_screen_position.distance_to(window_center).abs() > (window_center.y - 40.0) { - game_core.master_camera.target += player_real_movement; - } - - } - - fn render_player( - &mut self, - context_2d: &mut RaylibMode2D, - game_core: &mut GameCore, - ) { - // Get the player - let player = &game_core.player; - - // Convert the player direction to a rotation - let player_rotation = Vector2::zero().angle_to(player.direction); - - // TODO: tmp rect - context_2d.draw_rectangle_pro( - Rectangle { - x: player.position.x, - y: player.position.y, - width: player.size.x, - height: player.size.y, - }, - player.size / 2.0, - player_rotation.to_degrees() + 90.0, - Color::BLACK, - ); - } - fn render_world( &mut self, context_2d: &mut RaylibMode2D, game_core: &mut GameCore, ) { - context_2d.draw_circle(0, 0, 10.0, Color::BLACK); - } + + } impl Screen for InGameScreen { @@ -122,7 +46,7 @@ impl Screen for InGameScreen { game_core: &mut GameCore, ) -> Option { // Clear frame - draw_handle.clear_background(Color::WHITE); + draw_handle.clear_background(Color::BLUE); // Handle the pause menu being opened if draw_handle.is_key_pressed(KeyboardKey::KEY_ESCAPE) { @@ -138,7 +62,7 @@ impl Screen for InGameScreen { }; // Update player movement - self.update_player_movement(draw_handle, game_core, window_center); + playerlogic::update_player_movement(draw_handle, game_core, window_center); // Open a 2D context { @@ -148,7 +72,15 @@ impl Screen for InGameScreen { self.render_world(&mut context_2d, game_core); // Render Player - self.render_player(&mut context_2d, game_core); + playerlogic::render_player(&mut context_2d, game_core); + } + + // Render the hud + hud::render_hud(draw_handle, game_core, window_center); + + // Handle player out of breath + if game_core.player.breath_percent == 0.0 { + return Some(GameState::GameEnd); } return None; diff --git a/src/logic/ingame/playerlogic.rs b/src/logic/ingame/playerlogic.rs new file mode 100644 index 0000000..37c0a16 --- /dev/null +++ b/src/logic/ingame/playerlogic.rs @@ -0,0 +1,159 @@ +use raylib::prelude::*; + +use crate::{ + gamecore::GameCore, + pallette::{TRANSLUCENT_WHITE_128, TRANSLUCENT_WHITE_64, TRANSLUCENT_WHITE_96}, +}; + +const NORMAL_PLAYER_SPEED: i32 = 4; +const BOOST_PLAYER_SPEED: i32 = NORMAL_PLAYER_SPEED * 2; +const CAMERA_FOLLOW_SPEED: f32 = 0.7; +const TURN_SPEED: f32 = 0.05; +const BOOST_DECREASE_PER_SECOND: f32 = 0.75; +const BOOST_REGEN_PER_SECOND: f32 = 0.25; +const BREATH_DECREASE_PER_SECOND: f32 = 0.01; + +pub fn update_player_movement( + draw_handle: &mut RaylibDrawHandle, + game_core: &mut GameCore, + window_center: Vector2, +) { + // Calculate DT + let dt = draw_handle.get_time() - game_core.last_frame_time; + + // Handle player movement + let mouse_pose = draw_handle.get_mouse_position(); + let mouse_world_pose = draw_handle.get_screen_to_world2D(mouse_pose, game_core.master_camera); + let raw_movement_direction = mouse_world_pose - game_core.player.position; + let mut normalized_movement_direction = raw_movement_direction; + normalized_movement_direction.normalize(); + + let tau: f32 = PI as f32 * 2.0; + // get angles as floats + let mut player_angle: f32 = Vector2::zero().angle_to(game_core.player.direction); + let mut desired_angle: f32 = Vector2::zero().angle_to(normalized_movement_direction); + + // make angle positive + if desired_angle < 0.0 { + desired_angle += tau; + } + + // turn towards mouse at turn speed + if player_angle % tau > desired_angle { + if (player_angle % tau) - desired_angle > PI as f32 { + player_angle += TURN_SPEED; + } else { + player_angle -= TURN_SPEED; + } + } else { + if desired_angle - (player_angle % tau) > PI as f32 { + player_angle -= TURN_SPEED; + } else { + player_angle += TURN_SPEED; + } + } + + // snap to mouse if close enough + if f32::abs(player_angle - desired_angle) < (TURN_SPEED * 1.1) { + player_angle = desired_angle; + } + if player_angle > tau { + player_angle -= tau; + } + if player_angle < 0.0 { + player_angle += tau; + } + + // set angle + game_core.player.direction = Vector2::new(f32::cos(player_angle), f32::sin(player_angle)); + + // In the case the player is in "null", just jump the camera to them + if game_core.player.position == Vector2::zero() { + game_core.master_camera.target = game_core.player.position - (window_center / 2.0); + } + + // Handle action buttons + let user_request_boost = draw_handle.is_mouse_button_down(MouseButton::MOUSE_LEFT_BUTTON); + let user_request_action = draw_handle.is_mouse_button_pressed(MouseButton::MOUSE_RIGHT_BUTTON); + + // Move the player in their direction + let speed_multiplier; + if user_request_boost && game_core.player.boost_percent >= 0.0 { + // Set the speed multiplier + speed_multiplier = BOOST_PLAYER_SPEED as f32; + + // Decrease the boost + game_core.player.boost_percent -= BOOST_DECREASE_PER_SECOND * dt as f32; + } else { + // Set the speed multiplier + speed_multiplier = NORMAL_PLAYER_SPEED as f32; + + // Handle boost regen + if !user_request_boost { + game_core.player.boost_percent = (game_core.player.boost_percent + + BOOST_REGEN_PER_SECOND * dt as f32) + .clamp(0.0, 1.0); + } + } + + // Update the player's breath + game_core.player.breath_percent = + (game_core.player.breath_percent - BREATH_DECREASE_PER_SECOND * dt as f32).clamp(0.0, 1.0); + + // Only do this if the mouse is far enough away + let player_real_movement = game_core.player.direction * speed_multiplier; + if raw_movement_direction.distance_to(Vector2::zero()) > game_core.player.size.y / 2.0 { + game_core.player.position += player_real_movement; + } + + // Move the camera to follow the player + let direction_from_cam_to_player = + (game_core.player.position - window_center) - game_core.master_camera.target; + let player_screen_position = + draw_handle.get_world_to_screen2D(game_core.player.position, game_core.master_camera); + + // Camera only moves if you get close to the edge of the screen + if player_screen_position.distance_to(window_center).abs() > (window_center.y - 40.0) { + game_core.master_camera.target += player_real_movement; + } +} + +pub fn render_player(context_2d: &mut RaylibMode2D, game_core: &mut GameCore) { + // Get the player + let player = &game_core.player; + + // Convert the player direction to a rotation + let player_rotation = Vector2::zero().angle_to(player.direction); + + // Render the player's boost ring + // This functions both as a breath meter, and as a boost meter + let boost_ring_max_radius = player.size.x + 5.0; + context_2d.draw_circle( + player.position.x as i32, + player.position.y as i32, + boost_ring_max_radius * player.boost_percent, + TRANSLUCENT_WHITE_64, + ); + context_2d.draw_ring( + player.position, + boost_ring_max_radius - 2.0, + boost_ring_max_radius + 2.0, + 0, + (360.0 * player.breath_percent) as i32, + 0, + TRANSLUCENT_WHITE_96, + ); + + // TODO: tmp rect + context_2d.draw_rectangle_pro( + Rectangle { + x: player.position.x, + y: player.position.y, + width: player.size.x, + height: player.size.y, + }, + player.size / 2.0, + player_rotation.to_degrees() + 90.0, + Color::BLACK, + ); +} diff --git a/src/logic/mod.rs b/src/logic/mod.rs index 6d476b4..362eee2 100644 --- a/src/logic/mod.rs +++ b/src/logic/mod.rs @@ -2,4 +2,5 @@ pub mod screen; pub mod loadingscreen; pub mod mainmenu; pub mod pausemenu; -pub mod ingame; \ No newline at end of file +pub mod ingame; +pub mod gameend; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 241418d..85ff39b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,14 +4,12 @@ mod logic; mod resources; mod player; mod world; +mod pallette; use gamecore::{GameCore, GameState}; use lib::{utils::profiler::GameProfiler, wrappers::audio::player::AudioPlayer}; use log::info; -use logic::{ - ingame::InGameScreen, loadingscreen::LoadingScreen, mainmenu::MainMenuScreen, - pausemenu::PauseMenuScreen, screen::Screen, -}; +use logic::{gameend::GameEndScreen, ingame::InGameScreen, loadingscreen::LoadingScreen, mainmenu::MainMenuScreen, pausemenu::PauseMenuScreen, screen::Screen}; use raylib::prelude::*; use world::World; @@ -58,6 +56,7 @@ fn main() { let mut main_menu_screen = MainMenuScreen::new(); let mut pause_menu_screen = PauseMenuScreen::new(); let mut ingame_screen = InGameScreen::new(); + let mut game_end_screen = GameEndScreen::new(); // Main rendering loop while !raylib.window_should_close() { @@ -90,6 +89,12 @@ fn main() { &mut audio_system, &mut game_core, ), + GameState::GameEnd => game_end_screen.render( + &mut draw_handle, + &raylib_thread, + &mut audio_system, + &mut game_core, + ), }; // If needed, update the global state @@ -120,6 +125,9 @@ fn main() { profiler.data.audio_volume = audio_system.get_master_volume(); profiler.data.active_sounds = audio_system.get_sounds_playing(); profiler.data.game_state = game_core.state.to_string(); + profiler.data.player_coins = game_core.player.coins; + profiler.data.player_boost_percent = game_core.player.boost_percent; + profiler.data.player_breath_percent = game_core.player.breath_percent; // Send telemetry data profiler.update(); @@ -145,6 +153,9 @@ fn main() { // Set the first frame flag game_core.has_rendered_first_frame = true; + + // Update the frame time + game_core.last_frame_time = draw_handle.get_time(); } // Cleanup diff --git a/src/pallette.rs b/src/pallette.rs new file mode 100644 index 0000000..9d70e98 --- /dev/null +++ b/src/pallette.rs @@ -0,0 +1,22 @@ +use raylib::color::Color; + +pub const TRANSLUCENT_WHITE_128: Color = Color { + r: 255, + g: 255, + b: 255, + a: 128, +}; + +pub const TRANSLUCENT_WHITE_96: Color = Color { + r: 255, + g: 255, + b: 255, + a: 96, +}; + +pub const TRANSLUCENT_WHITE_64: Color = Color { + r: 255, + g: 255, + b: 255, + a: 64, +}; \ No newline at end of file diff --git a/src/player.rs b/src/player.rs index 3fa3a58..a455e9b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -8,7 +8,8 @@ pub struct Player { pub direction: Vector2, pub size: Vector2, pub coins: u32, - pub boost_percent: f32 + pub boost_percent: f32, + pub breath_percent: f32 } impl Player { @@ -19,6 +20,7 @@ impl Player { x: 11.0 * 4.0, y: 21.0 * 4.0 }, + breath_percent: 1.0, ..Default::default() } diff --git a/src/world.rs b/src/world.rs index 4600c51..309fd41 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,11 +1,14 @@ use std::{fs::File, io::BufReader}; +use raylib::math::Vector2; use serde::{Deserialize, Serialize}; use std::io::Read; use failure::Error; #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct World {} +pub struct World { + pub end_position: Vector2 +} impl World { pub fn load_from_json(file: String) -> Result {