diff --git a/README.md b/README.md
index 6bdda91..8543c25 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# \[Game Name\]
+# Deep Breath
[](https://github.com/Ewpratten/ludum-dare-48/actions/workflows/build.yml)
@@ -9,7 +9,11 @@
[](https://www.rust-lang.org/)
[](https://www.raylib.com/)
-*\[Game Name\]* is a ...
+**Deep Breath** is an exploration game where you explore an underwater cave in hopes of finding your lost transponder. Items and upgrades can be acquired along the way to assist your search.
+
+This game was written in [Rust](https://www.rust-lang.org/), on top of [Rust bindings](https://github.com/deltaphc/raylib-rs) to the [`raylib`](https://github.com/raysan5/raylib) graphics library. For most of the team, this has been our first big Rust project.
+
+This has been our second game produced for Ludum Dare. Check out the first [here](https://ldjam.com/events/ludum-dare/46/micromanaged-mike).
## Development Resources
diff --git a/assets/img/logos/readme-54.png b/assets/img/logos/readme-54.png
new file mode 100644
index 0000000..97f845b
Binary files /dev/null and b/assets/img/logos/readme-54.png differ
diff --git a/assets/img/logos/readme.png b/assets/img/logos/readme.png
index c86b506..d6fda2f 100644
Binary files a/assets/img/logos/readme.png and b/assets/img/logos/readme.png differ
diff --git a/assets/img/map/tutorial1.png b/assets/img/map/tutorial1.png
new file mode 100644
index 0000000..29f3a8b
Binary files /dev/null and b/assets/img/map/tutorial1.png differ
diff --git a/assets/img/map/tutorial2.png b/assets/img/map/tutorial2.png
new file mode 100644
index 0000000..3c55f05
Binary files /dev/null and b/assets/img/map/tutorial2.png differ
diff --git a/assets/worlds/mainworld.json b/assets/worlds/mainworld.json
index 368ba0d..d749e10 100644
--- a/assets/worlds/mainworld.json
+++ b/assets/worlds/mainworld.json
@@ -183,5 +183,113 @@
"should_remove": false,
"rotation": 0
}
+
+ ],
+ "pufferfish": [
+ {
+ "position" : {
+ "x": 261,
+ "y": 387
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x": 195,
+ "y": 694
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x": 635,
+ "y": 731
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x": 169,
+ "y": 1104
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x": 478,
+ "y": 1333
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x": 499,
+ "y": 1775
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x": 74,
+ "y": 1259
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ },
+ {
+ "position" : {
+ "x":260,
+ "y":1472
+ },
+ "is_knocking_back": false,
+ "time_knocking_back": 0.0,
+ "inflate_timer": 0.0,
+ "is_large": false,
+ "stun_timer": 0.0,
+ "puffer_state": "SmallIdle"
+
+ }
+
]
}
\ No newline at end of file
diff --git a/src/entities/enemy/mod.rs b/src/entities/enemy/mod.rs
index 18acd78..91246eb 100644
--- a/src/entities/enemy/mod.rs
+++ b/src/entities/enemy/mod.rs
@@ -1,4 +1,5 @@
pub mod base;
pub mod jellyfish;
pub mod octopus;
-pub mod whirlpool;
\ No newline at end of file
+pub mod whirlpool;
+pub mod pufferfish;
\ No newline at end of file
diff --git a/src/entities/enemy/pufferfish.rs b/src/entities/enemy/pufferfish.rs
new file mode 100644
index 0000000..6956ab8
--- /dev/null
+++ b/src/entities/enemy/pufferfish.rs
@@ -0,0 +1,156 @@
+use raylib::prelude::*;
+
+use serde::{Deserialize, Serialize};
+
+use crate::{lib::utils::calculate_linear_slide, pallette::TRANSLUCENT_RED_64};
+
+use super::base::EnemyBase;
+
+#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
+pub enum PufferState {
+ SmallIdle,
+ Growing,
+ LargeIdle,
+ Blowing,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct Pufferfish {
+ pub position: Vector2,
+ pub is_knocking_back: bool,
+ pub time_knocking_back: f64,
+
+ pub inflate_timer: f64,
+ pub is_large: bool,
+ pub stun_timer: f64,
+ pub puffer_state: PufferState,
+}
+
+impl EnemyBase for Pufferfish {
+ fn render(
+ &mut self,
+ context_2d: &mut RaylibMode2D,
+ player: &mut crate::player::Player,
+ resources: &mut crate::resources::GlobalResources,
+ dt: f64,
+ ) {
+
+ let is_stunned = self.stun_timer > 0.0;
+
+ // Render the stun ring
+ if is_stunned {
+ // println!("Stunned");
+ let stun_ring_alpha =
+ calculate_linear_slide(self.stun_timer / 1.0);
+ context_2d.draw_circle_v(
+ self.position,
+ 12.0,
+ TRANSLUCENT_RED_64.fade(0.55 * stun_ring_alpha as f32),
+ );
+
+ self.stun_timer -= dt;
+ }
+
+
+ let angle = player.position.angle_to(self.position).to_degrees();
+
+
+ match self.puffer_state {
+ PufferState::SmallIdle => {
+ resources.pufferfish_small.draw(
+ context_2d,
+ Vector2 {
+ x: self.position.x,
+ y: self.position.y,
+ },
+ angle,
+ );
+
+ if self.position.distance_to(player.position).abs() <= 100.0 && self.inflate_timer > 2.0{
+ self.puffer_state = PufferState::Growing;
+ }
+ self.is_large = false;
+ },
+ PufferState::Growing => {
+ self.inflate_timer = 0.0;
+ resources.pufferfish_expand.draw(
+ context_2d,
+ Vector2 {
+ x: self.position.x,
+ y: self.position.y,
+ },
+ angle,
+ );
+
+ if resources.pufferfish_expand.get_current_frame_id(context_2d) == 3 {
+ self.puffer_state = PufferState::LargeIdle;
+ }
+ self.is_large = true;
+
+ },
+ PufferState::LargeIdle => {
+ self.inflate_timer = 0.0;
+ resources.pufferfish_big.draw(
+ context_2d,
+ Vector2 {
+ x: self.position.x,
+ y: self.position.y,
+ },
+ angle,
+ );
+
+ if self.position.distance_to(player.position).abs() <= 65.0{
+ self.puffer_state = PufferState::Blowing;
+ self.is_knocking_back = true;
+ self.time_knocking_back = 0.0;
+ }
+
+ self.is_large = true;
+ },
+ PufferState::Blowing => {
+
+ resources.pufferfish_attack.draw(
+ context_2d,
+ Vector2 {
+ x: self.position.x,
+ y: self.position.y,
+ },
+ angle,
+ );
+
+
+ if resources.pufferfish_expand.get_current_frame_id(context_2d) == 3 && self.inflate_timer > 1.0{
+ self.puffer_state = PufferState::SmallIdle;
+ self.inflate_timer = 0.0;
+ }
+ self.is_large = false;
+ },
+ }
+ }
+
+ fn handle_logic(&mut self, player: &mut crate::player::Player, dt: f64) -> u8 {
+
+
+
+ self.inflate_timer += dt;
+ self.time_knocking_back += dt;
+
+ if self.time_knocking_back >= 0.5{
+ self.is_knocking_back = false;
+ }
+
+ if self.position.distance_to(player.position).abs() > 120.0 && self.is_large {
+ self.puffer_state = PufferState::Blowing;
+ self.inflate_timer = 0.0;
+ }
+
+ return 0;
+
+ }
+
+ fn handle_getting_attacked(&mut self, stun_duration: f64, current_time: f64) {
+
+ self.stun_timer = stun_duration;
+
+ }
+}
diff --git a/src/logic/ingame/mod.rs b/src/logic/ingame/mod.rs
index 2119974..786348c 100644
--- a/src/logic/ingame/mod.rs
+++ b/src/logic/ingame/mod.rs
@@ -268,6 +268,17 @@ impl Screen for InGameScreen {
}
+ // Iterates over pufferfish
+ for pufferfish in game_core.world.pufferfish.iter_mut(){
+
+ pufferfish.handle_logic(&mut game_core.player, dt);
+ pufferfish.render(&mut context_2d, &mut game_core.player, &mut game_core.resources, dt);
+
+
+
+ }
+
+
// Removes whirlpools set for removal
game_core.world.whirlpool.retain(|x| !x.should_remove());
diff --git a/src/logic/ingame/playerlogic.rs b/src/logic/ingame/playerlogic.rs
index efcb4fd..4e46216 100644
--- a/src/logic/ingame/playerlogic.rs
+++ b/src/logic/ingame/playerlogic.rs
@@ -86,7 +86,10 @@ pub fn update_player_movement(
game_core
.player
.begin_attack(&mut game_core.world, draw_handle.get_time());
- // println!("{{\"x\":{}, \"y\":{}}},",f32::round(game_core.player.position.x),f32::round(game_core.player.position.y));
+ }
+
+ if user_request_action {
+ // println!("{{\"x\":{}, \"y\":{}}},",f32::round(game_core.player.position.x),f32::round(game_core.player.position.y));
}
// die sound
@@ -235,6 +238,44 @@ pub fn update_player_movement(
}
+ for pufferfish in game_core.world.pufferfish.iter_mut(){
+
+ if pufferfish.is_knocking_back{
+ // Calculates info for formulas
+
+ // Deltas between positions
+ let net_pose = game_core.player.position - pufferfish.position;
+
+ // Angle between: UNITS: RADIANS
+ let angle = net_pose.y.atan2(net_pose.x);
+
+ // Calculates force
+ let force = 0.2;
+
+ // Calculates componets of force
+ let mut force_x = (force as f32 * angle.cos()).clamp(-1.0, 1.0);
+ let mut force_y = (force as f32 * angle.sin()).clamp(-1.0, 1.0);
+
+ // Prevents Nan erros
+ if force_x.is_nan(){
+ force_x = 1.0 * net_pose.x;
+ }
+
+ if force_y.is_nan(){
+ force_y = 1.0 * net_pose.y;
+ }
+
+ game_core.player.additional_vel.x += force_x;
+ game_core.player.additional_vel.y += force_y;
+
+ should_apply_friction = false;
+
+ }
+
+
+
+ }
+
if should_apply_friction {
game_core.player.additional_vel.x /= PLAYER_FRICTION;
game_core.player.additional_vel.y /= PLAYER_FRICTION;
diff --git a/src/logic/loadingscreen.rs b/src/logic/loadingscreen.rs
index ba13c53..df5293c 100644
--- a/src/logic/loadingscreen.rs
+++ b/src/logic/loadingscreen.rs
@@ -49,30 +49,30 @@ impl LoadingScreen {
win_height: i32,
win_width: i32,
) {
- // Determine how far through rendering this logo we are
- // This value is used to determine the logo alpha
- let playthrough_percent =
- (draw_handle.get_time() - self.last_state_switch_time) / SECONDS_PER_LOGO;
+ // // Determine how far through rendering this logo we are
+ // // This value is used to determine the logo alpha
+ // let playthrough_percent =
+ // (draw_handle.get_time() - self.last_state_switch_time) / SECONDS_PER_LOGO;
- // Build a color mask
- let mask = self.get_logo_mask(playthrough_percent);
+ // // Build a color mask
+ // let mask = self.get_logo_mask(playthrough_percent);
- // Get the logo
- let logo = &game_core.resources.game_logo;
+ // // Get the logo
+ // let logo = &game_core.resources.game_logo;
- // Render the logo
- draw_handle.draw_texture(
- logo,
- (win_width / 2) - (logo.width / 2),
- (win_height / 2) - (logo.height / 2),
- mask,
- );
+ // // Render the logo
+ // draw_handle.draw_texture(
+ // logo,
+ // (win_width / 2) - (logo.width / 2),
+ // (win_height / 2) - (logo.height / 2),
+ // mask,
+ // );
// Move on to next logo if needed
- if playthrough_percent >= 1.0 {
+ // if playthrough_percent >= 1.0 {
self.state = LoadingScreenState::RaylibLogo;
self.last_state_switch_time = draw_handle.get_time();
- }
+ // }
}
fn show_raylib_logo(
diff --git a/src/logic/mainmenu.rs b/src/logic/mainmenu.rs
index 471a8fd..de45d6d 100644
--- a/src/logic/mainmenu.rs
+++ b/src/logic/mainmenu.rs
@@ -34,8 +34,8 @@ impl Screen for MainMenuScreen {
// Render title
draw_handle.draw_text(
- "ONE BREATH",
- (win_height / 2) - 80,
+ "DEEP BREATH",
+ (win_height / 2) - 100,
win_width / 8,
80,
Color::BLACK,
diff --git a/src/main.rs b/src/main.rs
index 659cccc..00efc56 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -23,7 +23,7 @@ const DEFAULT_WINDOW_DIMENSIONS: Vector2 = Vector2 {
x: 1080.0,
y: 720.0,
};
-const WINDOW_TITLE: &str = r"One Breath";
+const WINDOW_TITLE: &str = r"Deep Breath";
const MAX_FPS: u32 = 60;
fn main() {
diff --git a/src/player.rs b/src/player.rs
index 83046eb..0ae243a 100644
--- a/src/player.rs
+++ b/src/player.rs
@@ -106,6 +106,11 @@ impl Player {
if whirlpool.position.distance_to(self.position).abs() <= stun_reach {
whirlpool.handle_getting_attacked(self.attacking_timer, current_time);
}
+ }
+ for pufferfish in world.pufferfish.iter_mut() {
+ if pufferfish.position.distance_to(self.position).abs() <= stun_reach {
+ pufferfish.handle_getting_attacked(self.attacking_timer, current_time);
+ }
}
}
}
diff --git a/src/resources.rs b/src/resources.rs
index e5c6f92..ce8340f 100644
--- a/src/resources.rs
+++ b/src/resources.rs
@@ -28,6 +28,10 @@ pub struct GlobalResources {
pub octopus_animation_regular: FrameAnimationWrapper,
pub octopus_animation_attack: FrameAnimationWrapper,
pub whirlpool: FrameAnimationWrapper,
+ pub pufferfish_big: FrameAnimationWrapper,
+ pub pufferfish_small: FrameAnimationWrapper,
+ pub pufferfish_attack: FrameAnimationWrapper,
+ pub pufferfish_expand: FrameAnimationWrapper,
// Darkness layer
pub darkness_overlay: Texture2D,
@@ -267,6 +271,42 @@ impl GlobalResources {
4,
4,
),
+ pufferfish_big: FrameAnimationWrapper::new(
+ raylib.load_texture_from_image(
+ &thread,
+ &Image::load_image("./assets/img/enemies/pufferFishBigIdle.png")?,
+ )?,
+ Vector2 { x: 19.0, y: 19.0 },
+ 3,
+ 4,
+ ),
+ pufferfish_small: FrameAnimationWrapper::new(
+ raylib.load_texture_from_image(
+ &thread,
+ &Image::load_image("./assets/img/enemies/pufferFishIdle.png")?,
+ )?,
+ Vector2 { x: 19.0, y: 19.0 },
+ 6,
+ 4,
+ ),
+ pufferfish_attack: FrameAnimationWrapper::new(
+ raylib.load_texture_from_image(
+ &thread,
+ &Image::load_image("./assets/img/enemies/pufferFishAttack.png")?,
+ )?,
+ Vector2 { x: 39.0, y: 25.0 },
+ 4,
+ 4,
+ ),
+ pufferfish_expand: FrameAnimationWrapper::new(
+ raylib.load_texture_from_image(
+ &thread,
+ &Image::load_image("./assets/img/enemies/pufferFishExpand.png")?,
+ )?,
+ Vector2 { x: 19.0, y: 19.0 },
+ 4,
+ 4,
+ ),
breath: Sound::load_sound("./assets/audio/breath.mp3")?,
swim1: Sound::load_sound("./assets/audio/swim1.mp3")?,
swim2: Sound::load_sound("./assets/audio/swim2.mp3")?,
diff --git a/src/world.rs b/src/world.rs
index e1e1e00..15f592b 100644
--- a/src/world.rs
+++ b/src/world.rs
@@ -4,14 +4,7 @@ use failure::Error;
use raylib::math::{Rectangle, Vector2};
use serde::{Deserialize, Serialize};
-use crate::{
- entities::{
- enemy::{jellyfish::JellyFish, octopus::Octopus, whirlpool::Whirlpool,},
- fish::FishEntity,
-
- },
- player::Player,
-};
+use crate::{entities::{enemy::{jellyfish::JellyFish, octopus::Octopus, pufferfish::Pufferfish, whirlpool::Whirlpool}, fish::FishEntity}, player::Player};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct World {
@@ -31,6 +24,7 @@ pub struct World {
pub jellyfish: Vec,
pub octopus: Vec,
pub whirlpool: Vec,
+ pub pufferfish: Vec
}