diff --git a/assets/img/map/fish.aseprite b/assets/img/map/fish.aseprite new file mode 100644 index 0000000..1883247 Binary files /dev/null and b/assets/img/map/fish.aseprite differ diff --git a/assets/img/map/fish.json b/assets/img/map/fish.json new file mode 100644 index 0000000..324ec8a --- /dev/null +++ b/assets/img/map/fish.json @@ -0,0 +1,26 @@ +{ "frames": { + "fish 62.aseprite": { + "frame": { "x": 806, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 50 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.2.27-x64", + "image": "fish.png", + "format": "RGBA8888", + "size": { "w": 819, "h": 9 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } + ], + "slices": [ + ] + } +} diff --git a/assets/img/map/fish.png b/assets/img/map/fish.png new file mode 100644 index 0000000..29054a8 Binary files /dev/null and b/assets/img/map/fish.png differ diff --git a/assets/img/map/fishIdle.aseprite b/assets/img/map/fishIdle.aseprite new file mode 100644 index 0000000..6514d45 Binary files /dev/null and b/assets/img/map/fishIdle.aseprite differ diff --git a/assets/img/map/fishIdle.json b/assets/img/map/fishIdle.json new file mode 100644 index 0000000..f8f5e3b --- /dev/null +++ b/assets/img/map/fishIdle.json @@ -0,0 +1,130 @@ +{ "frames": { + "fishIdle 0.aseprite": { + "frame": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 1.aseprite": { + "frame": { "x": 13, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 2.aseprite": { + "frame": { "x": 26, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 3.aseprite": { + "frame": { "x": 39, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 4.aseprite": { + "frame": { "x": 52, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 5.aseprite": { + "frame": { "x": 65, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 6.aseprite": { + "frame": { "x": 78, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 7.aseprite": { + "frame": { "x": 91, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 8.aseprite": { + "frame": { "x": 104, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 9.aseprite": { + "frame": { "x": 117, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 10.aseprite": { + "frame": { "x": 130, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 11.aseprite": { + "frame": { "x": 143, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 12.aseprite": { + "frame": { "x": 156, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + }, + "fishIdle 13.aseprite": { + "frame": { "x": 169, "y": 0, "w": 13, "h": 9 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 9 }, + "sourceSize": { "w": 13, "h": 9 }, + "duration": 100 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.2.27-x64", + "image": "fishIdle.png", + "format": "RGBA8888", + "size": { "w": 182, "h": 9 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } + ], + "slices": [ + ] + } +} diff --git a/assets/img/map/fishIdle.png b/assets/img/map/fishIdle.png new file mode 100644 index 0000000..44c6967 Binary files /dev/null and b/assets/img/map/fishIdle.png differ diff --git a/src/entities/fish.rs b/src/entities/fish.rs index 8982d0b..4cc266e 100644 --- a/src/entities/fish.rs +++ b/src/entities/fish.rs @@ -1,9 +1,7 @@ use rand::{prelude::ThreadRng, Rng}; use raylib::prelude::*; -use crate::{ - gamecore::GameCore, lib::utils::triangles::rotate_vector, player::Player, world::World, -}; +use crate::{gamecore::{self, GameCore}, lib::utils::triangles::rotate_vector, player::Player, resources::GlobalResources, world::World}; const FISH_FOLLOW_PLAYER_DISTANCE: f32 = 30.0; const FISH_FOLLOW_PLAYER_SPEED: f32 = 1.8; @@ -25,9 +23,11 @@ pub struct FishEntity { direction: Vector2, velocity: Vector2, pub following_player: bool, + current_frame: u8, + animation_counter: u32, size: Vector2, + color: u8, rng: ThreadRng, - color: Color, } impl FishEntity { @@ -38,13 +38,10 @@ impl FishEntity { direction: Vector2::zero(), velocity: Vector2::zero(), following_player: false, + animation_counter: 0, + current_frame: 0, size: Vector2 { x: 5.0, y: 8.0 }, - color: Color { - r: rng.gen_range(128..225), - g: rng.gen_range(128..225), - b: rng.gen_range(128..225), - a: 140, - }, + color: rng.gen_range(0..6), rng, } } @@ -138,21 +135,17 @@ impl FishEntity { // Distance and direction to player let dist_to_player = player.position - self.position; let dist_to_player_lin = self.position.distance_to(player.position); - let mut direction_to_player = dist_to_player; - direction_to_player.normalize(); // Handle player picking up fish if player.position.distance_to(self.position).abs() <= player.size.y * 2.2 { self.following_player = true; self.velocity = self.direction.normalized(); + self.current_frame = 0; + self.animation_counter = 0; // Add currency to the player player.coins += 1; } - - // Look at the player; - self.position = self.position; - self.direction = direction_to_player; } pub fn update_position(&mut self, player: &mut Player, dt: f64, other_fish: &Vec) { @@ -163,40 +156,37 @@ impl FishEntity { } } - pub fn render(&self, context_2d: &mut RaylibMode2D) { + pub fn render(&mut self, context_2d: &mut RaylibMode2D, resources: &mut GlobalResources) { // Direction let direction = Vector2::zero().angle_to(self.direction.normalized()) + (90.0 as f32).to_radians(); - // Get the corners of the fish - let fish_front = rotate_vector( - Vector2 { - x: 0.0, - y: (self.size.y / 2.0) * -1.0, - }, - direction, - ); - let fish_bl = rotate_vector( - Vector2 { - x: (self.size.x / 2.0) * -1.0, - y: (self.size.y / 2.0), - }, - direction, - ); - let fish_br = rotate_vector( - Vector2 { - x: (self.size.x / 2.0), - y: (self.size.y / 2.0), - }, - direction, - ); + self.animation_counter += 1; - // Draw the fish as a triangle with rotation - context_2d.draw_triangle( - self.position + fish_front, - self.position + fish_bl, - self.position + fish_br, - self.color, - ); + // swimming + if self.following_player { + if self.animation_counter % 3 == 0 { + if self.current_frame == 8 { + self.current_frame = 0; + } + } + resources.fish_animation_swim.draw_frame(context_2d, + self.position, + direction, + (self.current_frame + self.color * 9) as u32); + // idle + } else { + if self.animation_counter % 10 == 0 { + if self.current_frame == 0 { + self.current_frame = 1; + } else { + self.current_frame = 0; + } + } + resources.fish_animation_idle.draw_frame(context_2d, + self.position, + direction, + (self.current_frame + self.color * 2) as u32); + } } } diff --git a/src/logic/ingame/mod.rs b/src/logic/ingame/mod.rs index 3f2bce6..ea95cf2 100644 --- a/src/logic/ingame/mod.rs +++ b/src/logic/ingame/mod.rs @@ -62,7 +62,7 @@ impl InGameScreen { let fish_clone = game_core.world.fish.clone(); for fish in game_core.world.fish.iter_mut() { fish.update_position(&mut game_core.player, dt, &fish_clone); - fish.render(context_2d); + fish.render(context_2d, &mut game_core.resources); } // Render the world texture diff --git a/src/resources.rs b/src/resources.rs index 03cd78c..3e7b27a 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -17,6 +17,10 @@ pub struct GlobalResources { pub player_animation_boost_charge: FrameAnimationWrapper, pub player_animation_boost: FrameAnimationWrapper, pub player_animation_stunned: FrameAnimationWrapper, + + // Fish + pub fish_animation_idle: FrameAnimationWrapper, + pub fish_animation_swim: FrameAnimationWrapper, // Cave pub cave_mid_layer: Texture2D, @@ -76,6 +80,24 @@ impl GlobalResources { 4, 100 / 8, ), + fish_animation_idle: FrameAnimationWrapper::new( + raylib.load_texture_from_image( + &thread, + &Image::load_image("./assets/img/map/fishIdle.png")?, + )?, + Vector2 { x: 13.0, y: 9.0 }, + 14, + 4, + ), + fish_animation_swim: FrameAnimationWrapper::new( + raylib.load_texture_from_image( + &thread, + &Image::load_image("./assets/img/map/fish.png")?, + )?, + Vector2 { x: 13.0, y: 9.0 }, + 63, + 30, + ), cave_mid_layer: raylib.load_texture_from_image( &thread, &Image::load_image("./assets/img/map/cave.png")?,