diff --git a/assets/audio/breath.mp3 b/assets/audio/breath.mp3 new file mode 100644 index 0000000..4b903a5 Binary files /dev/null and b/assets/audio/breath.mp3 differ diff --git a/assets/audio/die.mp3 b/assets/audio/die.mp3 new file mode 100644 index 0000000..128c504 Binary files /dev/null and b/assets/audio/die.mp3 differ diff --git a/assets/audio/fishPickup.mp3 b/assets/audio/fishPickup.mp3 new file mode 100644 index 0000000..c4e79bd Binary files /dev/null and b/assets/audio/fishPickup.mp3 differ diff --git a/assets/audio/swim1.mp3 b/assets/audio/swim1.mp3 new file mode 100644 index 0000000..1b19675 Binary files /dev/null and b/assets/audio/swim1.mp3 differ diff --git a/assets/audio/swim2.mp3 b/assets/audio/swim2.mp3 new file mode 100644 index 0000000..5d89251 Binary files /dev/null and b/assets/audio/swim2.mp3 differ diff --git a/assets/audio/swim3.mp3 b/assets/audio/swim3.mp3 new file mode 100644 index 0000000..8686edb Binary files /dev/null and b/assets/audio/swim3.mp3 differ diff --git a/assets/audio/swim4.mp3 b/assets/audio/swim4.mp3 new file mode 100644 index 0000000..20256ce Binary files /dev/null and b/assets/audio/swim4.mp3 differ diff --git a/assets/audio/uiBuy.mp3 b/assets/audio/uiBuy.mp3 new file mode 100644 index 0000000..47bcb39 Binary files /dev/null and b/assets/audio/uiBuy.mp3 differ diff --git a/assets/audio/uiClick.mp3 b/assets/audio/uiClick.mp3 new file mode 100644 index 0000000..a6079ff Binary files /dev/null and b/assets/audio/uiClick.mp3 differ diff --git a/assets/audio/waterrecordings.wav b/assets/audio/waterrecordings.wav new file mode 100644 index 0000000..d86366f Binary files /dev/null and b/assets/audio/waterrecordings.wav differ diff --git a/assets/img/enemies/whirlpool.aseprite b/assets/img/enemies/whirlpool.aseprite new file mode 100644 index 0000000..f85c550 Binary files /dev/null and b/assets/img/enemies/whirlpool.aseprite differ diff --git a/assets/img/enemies/whirlpool.json b/assets/img/enemies/whirlpool.json new file mode 100644 index 0000000..21c2e0d --- /dev/null +++ b/assets/img/enemies/whirlpool.json @@ -0,0 +1,51 @@ +{ "frames": { + "whirlpool 0.aseprite": { + "frame": { "x": 0, "y": 0, "w": 20, "h": 20 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 20 }, + "sourceSize": { "w": 20, "h": 20 }, + "duration": 300 + }, + "whirlpool 1.aseprite": { + "frame": { "x": 20, "y": 0, "w": 20, "h": 20 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 20 }, + "sourceSize": { "w": 20, "h": 20 }, + "duration": 300 + }, + "whirlpool 2.aseprite": { + "frame": { "x": 40, "y": 0, "w": 20, "h": 20 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 20 }, + "sourceSize": { "w": 20, "h": 20 }, + "duration": 300 + }, + "whirlpool 3.aseprite": { + "frame": { "x": 60, "y": 0, "w": 20, "h": 20 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 20 }, + "sourceSize": { "w": 20, "h": 20 }, + "duration": 300 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.2.27-x64", + "image": "whirlpool.png", + "format": "RGBA8888", + "size": { "w": 80, "h": 20 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" }, + { "name": "Layer 2", "opacity": 255, "blendMode": "normal" } + ], + "slices": [ + ] + } +} diff --git a/assets/img/enemies/whirlpool.png b/assets/img/enemies/whirlpool.png new file mode 100644 index 0000000..2e9d310 Binary files /dev/null and b/assets/img/enemies/whirlpool.png differ diff --git a/assets/worlds/mainworld.json b/assets/worlds/mainworld.json index 17ce35c..9c46d40 100644 --- a/assets/worlds/mainworld.json +++ b/assets/worlds/mainworld.json @@ -29,5 +29,16 @@ "y": 100 } } - ] + ], + "whirlpool": [ + { + "position" : { + "x": 250, + "y": 250 + }, + "should_remove": false, + "rotation": 0 + } + + ] } \ No newline at end of file diff --git a/src/entities/enemy/mod.rs b/src/entities/enemy/mod.rs index 1189f2b..18acd78 100644 --- a/src/entities/enemy/mod.rs +++ b/src/entities/enemy/mod.rs @@ -1,3 +1,4 @@ pub mod base; pub mod jellyfish; -pub mod octopus; \ No newline at end of file +pub mod octopus; +pub mod whirlpool; \ No newline at end of file diff --git a/src/entities/enemy/whirlpool.rs b/src/entities/enemy/whirlpool.rs new file mode 100644 index 0000000..a2b7bf0 --- /dev/null +++ b/src/entities/enemy/whirlpool.rs @@ -0,0 +1,52 @@ +use raylib::prelude::*; + +use super::base::EnemyBase; + +use serde::{Deserialize, Serialize}; + + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Whirlpool{ + pub position: Vector2, + + // Track if it needs removing + pub should_remove: bool, + + // variable for tracking rotation + pub rotation: f32, +} + +impl Whirlpool{ + + // hook to see if item needs removing + pub fn should_remove(&self) -> bool{ + return self.should_remove; + } + +} + +impl EnemyBase for Whirlpool{ + fn render( + &mut self, + context_2d: &mut RaylibMode2D, + player: &mut crate::player::Player, + resources: &mut crate::resources::GlobalResources, + dt: f64, + ) { + + resources.whirlpool.draw(context_2d, Vector2{x: self.position.x, y: self.position.y}, self.rotation); + self.rotation += 1.0; + } + + fn handle_logic(&mut self, player: &mut crate::player::Player, dt: f64) { + + } + + // Whirlpool removed if shoot + fn handle_getting_attacked(&mut self, stun_duration: f64, current_time: f64) { + self.should_remove = true; + } + + + +} \ No newline at end of file diff --git a/src/logic/ingame/mod.rs b/src/logic/ingame/mod.rs index d989183..85bebba 100644 --- a/src/logic/ingame/mod.rs +++ b/src/logic/ingame/mod.rs @@ -3,13 +3,11 @@ mod playerlogic; use raylib::prelude::*; -use crate::{ - entities::enemy::base::EnemyBase, - gamecore::{GameCore, GameState}, - lib::wrappers::audio::player::AudioPlayer, -}; +use crate::{entities::enemy::{base::EnemyBase, whirlpool::Whirlpool}, gamecore::{GameCore, GameState}, lib::wrappers::audio::player::AudioPlayer}; use super::screen::Screen; +use crate::entities::fish::FishEntity; + pub struct InGameScreen { shader_time_var_location: i32, @@ -240,6 +238,27 @@ impl Screen for InGameScreen { ); } + // Iterates over whirlpools and runs render and logic funcs + for whirlpool_mob in game_core.world.whirlpool.iter_mut(){ + whirlpool_mob.handle_logic(&mut game_core.player, dt); + whirlpool_mob.render(&mut context_2d, &mut game_core.player, &mut game_core.resources, dt); + + // Spawns 10 fish on spawn + if whirlpool_mob.should_remove(){ + for _ in 0..10{ + game_core.world.fish.push(FishEntity::new(whirlpool_mob.position)); + } + } + + + } + + // Removes whirlpools set for removal + game_core.world.whirlpool.retain(|x| !x.should_remove()); + + + + // Render transponder game_core.resources.transponder.draw( &mut context_2d, diff --git a/src/logic/ingame/playerlogic.rs b/src/logic/ingame/playerlogic.rs index 3988da3..093ece8 100644 --- a/src/logic/ingame/playerlogic.rs +++ b/src/logic/ingame/playerlogic.rs @@ -20,7 +20,7 @@ pub fn update_player_movement( // 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 raw_movement_direction = mouse_world_pose - game_core.player.position; let mut normalized_movement_direction = raw_movement_direction; normalized_movement_direction.normalize(); @@ -157,6 +157,70 @@ pub fn update_player_movement( .speed_increase; } + + + + // Creates variable to calculate the distant + let mut movement_drift = Vector2::new(0.0, 0.0); + + // Check each whirlpool for effects + for whirlpool in game_core.world.whirlpool.iter_mut(){ + + + // check if its in range and not to close + if game_core.player.position.distance_to(whirlpool.position) <= 100.0 && game_core.player.position.distance_to(whirlpool.position) >= 10.0{ + + // Calculates info for formulas + + // Deltas between positions + let net_pose = game_core.player.position - whirlpool.position; + + // Angle between: UNITS: RADIANS + let angle = net_pose.y.atan2(net_pose.x); + + + // Calculates force + let force = 15.0 / game_core.player.position.distance_to(whirlpool.position); + + // Calculates componets of force + let mut force_x = (force as f32 * angle.cos()).clamp(-5.0, 5.0); + let mut force_y = (force as f32 * angle.sin()).clamp(-5.0, 5.0); + + // Prevents Nan erros + if force_x.is_nan(){ + force_x = 5.0 * net_pose.x; + } + + if force_y.is_nan(){ + force_y = 5.0 * net_pose.y; + } + + // Adds values to drift tracker + movement_drift.x -= force_x; + movement_drift.y -= force_y; + + } + + } + + // Checks collision + game_core.player.position.x += movement_drift.x; + for collider in game_core.world.colliders.iter() { + if game_core.player.collides_with_rec(collider) { + game_core.player.position.x -= movement_drift.x; + break; + } + } + + game_core.player.position.y += movement_drift.y; + for collider in game_core.world.colliders.iter() { + if game_core.player.collides_with_rec(collider) { + game_core.player.position.y -= movement_drift.y; + break; + } + } + + // Handle movement and collisions if raw_movement_direction.distance_to(Vector2::zero()) > game_core.player.size.y / 2.0 && !game_core.player.is_stunned() @@ -191,7 +255,12 @@ pub fn update_player_movement( // Handle updating the stun timer if player_stunned { game_core.player.stun_timer -= dt; - } + } + + + + + // Move the camera to follow the player let player_screen_position = @@ -199,7 +268,7 @@ pub fn update_player_movement( // Camera only moves if you get close to the edge of the screen if player_screen_position.distance_to(window_center).abs() > 100.0 { - game_core.master_camera.target += player_real_movement; + game_core.master_camera.target += player_real_movement + movement_drift; } // If the player is not on screen, snap the camera to them diff --git a/src/player.rs b/src/player.rs index 127a5fc..4e4f135 100644 --- a/src/player.rs +++ b/src/player.rs @@ -96,6 +96,11 @@ impl Player { if octopus.current_position.distance_to(self.position).abs() <= stun_reach { octopus.handle_getting_attacked(self.attacking_timer, current_time); } + } + for whirlpool in world.whirlpool.iter_mut() { + if whirlpool.position.distance_to(self.position).abs() <= stun_reach { + whirlpool.handle_getting_attacked(self.attacking_timer, current_time); + } } } } diff --git a/src/resources.rs b/src/resources.rs index cac06cb..35b16ac 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -32,6 +32,7 @@ pub struct GlobalResources { pub jellyfish_animation_attack: FrameAnimationWrapper, pub octopus_animation_regular: FrameAnimationWrapper, pub octopus_animation_attack: FrameAnimationWrapper, + pub whirlpool: FrameAnimationWrapper, // Darkness layer pub darkness_overlay: Texture2D, @@ -247,6 +248,15 @@ impl GlobalResources { 6, 2, ), + whirlpool: FrameAnimationWrapper::new( + raylib.load_texture_from_image( + &thread, + &Image::load_image("./assets/img/enemies/whirlpool.png")?, + )?, + Vector2 { x: 20.0, y: 20.0 }, + 4, + 4, + ), }) } } diff --git a/src/world.rs b/src/world.rs index 84629c3..e1e1e00 100644 --- a/src/world.rs +++ b/src/world.rs @@ -6,8 +6,9 @@ use serde::{Deserialize, Serialize}; use crate::{ entities::{ - enemy::{jellyfish::JellyFish, octopus::Octopus}, + enemy::{jellyfish::JellyFish, octopus::Octopus, whirlpool::Whirlpool,}, fish::FishEntity, + }, player::Player, }; @@ -26,8 +27,11 @@ pub struct World { #[serde(skip)] pub colliders: Vec, + // Mobs pub jellyfish: Vec, pub octopus: Vec, + pub whirlpool: Vec, + } impl World { @@ -53,6 +57,8 @@ impl World { }); } + + Ok(result) }