diff --git a/src/bubble.rs b/src/bubble.rs index 4f1d05c..2027c03 100644 --- a/src/bubble.rs +++ b/src/bubble.rs @@ -1,4 +1,4 @@ -use std::{f32::consts::TAU, fmt::Debug}; +use std::f32::consts::TAU; use bevy::prelude::*; use rand::Rng; @@ -8,10 +8,11 @@ use crate::{ kirby::Kirby, life::{DamageDealer, Life}, physics_body::PhysicsBody, + sphere_collider::SphereCollider, }; #[derive(Component)] -#[require(Sprite, PhysicsBody, DensityObject, Life, DamageDealer)] +#[require(Sprite, PhysicsBody, DensityObject, Life, DamageDealer, SphereCollider)] pub struct Bubble { move_force: f32, } @@ -27,10 +28,11 @@ pub fn bubble_spawn(mut commands: Commands, asset_server: Res) { commands.spawn(( Bubble { move_force: 3000.0 }, Sprite { image: texture.clone(), ..default() }, - Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(1.0)), PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 }, + Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(1.0)), Life::new(10.0), DamageDealer::new(0.5), + SphereCollider::new(20.0), )); } } @@ -55,3 +57,11 @@ pub fn bubble_move( bubble_body.force += dir * bubble.move_force; } } + +pub struct BubblePlugin; + +impl Plugin for BubblePlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, bubble_spawn).add_systems(FixedUpdate, bubble_move); + } +} diff --git a/src/camera.rs b/src/camera.rs index 7f202b7..44cc1da 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,5 +1,51 @@ +use std::f32::consts::TAU; + use bevy::{prelude::*, render::renderer}; -pub fn spawn_camera(mut commands: Commands) { - commands.spawn(Camera2d); +use crate::counter::KirbyHitCountThisFrame; + +#[derive(Component)] +pub struct MyCamera { + shaking_intensity_factor: f32, + shaking_reset_speed: f32, +} + +pub fn spawn_camera(mut commands: Commands) { + let mycam = commands + .spawn(( + MyCamera { shaking_intensity_factor: 10.0, shaking_reset_speed: 0.1 }, + Transform::from_translation(Vec3::ZERO), + )) + .id(); + commands.entity(mycam).with_child((Camera2d, Transform::from_xyz(0.0, 0.0, 0.0))); +} + +pub fn camera_shake( + time: Res>, + kirby_hit_count: Res, + parent_query: Query<(&MyCamera, &Children)>, + mut children_query: Query<&mut Transform, With>, +) { + let (parent, children) = parent_query.single().expect("Expect exactly one MyCamera entity"); + let child = children.first().expect("MyCamera must have at least one child Camera2d"); + let mut child_transform = children_query.get_mut(*child).expect("Camera child must have a Transform and Camera2d"); + + let rand_angle = rand::random_range(0.0..TAU); + let rand_vec = Vec2::from_angle(rand_angle); + let shaking_strength = kirby_hit_count.count as f32 * parent.shaking_intensity_factor; + let shaking_vec = rand_vec * shaking_strength; + let mut child_translation = child_transform.translation.clone(); + child_translation += shaking_vec.extend(0.0); + child_translation -= child_translation * parent.shaking_reset_speed * time.delta_secs(); + child_transform.translation.x = child_translation.x; + child_transform.translation.y = child_translation.y; + // println!("{:?}", child_transform.translation); +} + +pub struct MyCameraPlugin; + +impl Plugin for MyCameraPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, spawn_camera).add_systems(FixedPostUpdate, camera_shake); + } } diff --git a/src/counter.rs b/src/counter.rs new file mode 100644 index 0000000..86211a6 --- /dev/null +++ b/src/counter.rs @@ -0,0 +1,51 @@ +use bevy::prelude::*; +use derive_more::{Deref, DerefMut}; + +#[derive(Resource, Default)] +pub struct Counter { + pub count: u32, +} + +impl Counter { + pub fn new() -> Self { + Counter { count: 0 } + } + + pub fn increase(&mut self, delta: u32) { + self.count += delta; + } + + pub fn reset(&mut self) { + self.count = 0; + } +} + +#[derive(Resource, Default, Deref, DerefMut)] +pub struct BubbleExplodedCountThisFrame(pub Counter); + +#[derive(Resource, Default, Deref, DerefMut)] +pub struct BubbleSuckedCountThisFrame(pub Counter); + +#[derive(Resource, Default, Deref, DerefMut)] +pub struct KirbyHitCountThisFrame(pub Counter); + +fn reset_frame_counters( + mut bubble_sucked: ResMut, + mut bubble_exploded: ResMut, + mut kirby_hit: ResMut, +) { + bubble_sucked.reset(); + bubble_exploded.reset(); + kirby_hit.reset(); +} + +pub struct CounterPlugin; + +impl Plugin for CounterPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(BubbleSuckedCountThisFrame::default()) + .insert_resource(BubbleExplodedCountThisFrame::default()) + .insert_resource(KirbyHitCountThisFrame::default()) + .add_systems(FixedPostUpdate, reset_frame_counters); + } +} diff --git a/src/density_grid.rs b/src/density_grid.rs index 4b3c8df..9daf6fd 100644 --- a/src/density_grid.rs +++ b/src/density_grid.rs @@ -52,7 +52,7 @@ pub fn init_density_object(mut density_grid: ResMut, mut query: Que } } -pub fn density_grid_update(mut density_grid: ResMut, query: Query<&Transform>) { +pub fn density_grid_update(mut density_grid: ResMut, query: Query<&Transform, With>) { density_grid.grid.fill(0); for transform in &query { @@ -86,3 +86,13 @@ pub fn density_grid_force( physics_body.force -= density_gradient * DENSITY_FORCE_SCALE; } } + +pub struct DensityGridPlugin; + +impl Plugin for DensityGridPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(DensityGrid::new()) + .add_systems(PostStartup, init_density_object) + .add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain()); + } +} diff --git a/src/kirby.rs b/src/kirby.rs index 0a443b1..cd1da04 100644 --- a/src/kirby.rs +++ b/src/kirby.rs @@ -26,7 +26,6 @@ pub fn kirby_spawn( mut texture_atlas_layouts: ResMut>, ) { let texture: Handle = asset_server.load("sprites/Sprite_kirby-Sheet.png"); - let body = PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 }; let layout = TextureAtlasLayout::from_grid(UVec2::splat(32), 3, 3, None, None); let texture_atlas_layout = texture_atlas_layouts.add(layout); let animation_indices = AnimationIndices { first: 3, last: 5 }; // idle @@ -38,22 +37,21 @@ pub fn kirby_spawn( texture, TextureAtlas { layout: texture_atlas_layout, index: animation_indices.first }, ), - Transform::from_scale(Vec3::splat(KIRBY_SCALE)), + PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 }, + SphereCollider::new(20.0), animation_indices, AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)), - body, - SphereCollider::new(50.0), + Life::new(1000.0), + Transform::from_scale(Vec3::splat(KIRBY_SCALE)), )) .id(); - commands.entity(kirby_entity).with_children(|parent| { - parent.spawn(( - Transform::from_xyz(40.0, 0.0, 0.0), - SuckArea, - SphereCollider::new(80.0), - DamageDealer::new(10000.0), - )); - }); + commands.entity(kirby_entity).with_child(( + Transform::from_xyz(40.0, 0.0, 0.0), + SuckArea, + SphereCollider::new(80.0), + DamageDealer::new(10000.0), + )); } pub fn get_dir(keys: Res>) -> Vec2 { @@ -106,3 +104,10 @@ pub fn kirby_actions( } } } +pub struct KirbyPlugin; + +impl Plugin for KirbyPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, kirby_spawn).add_systems(FixedUpdate, kirby_actions); + } +} diff --git a/src/life.rs b/src/life.rs index 5ea0248..570e2c3 100644 --- a/src/life.rs +++ b/src/life.rs @@ -2,6 +2,7 @@ use bevy::prelude::*; use crate::{ bubble::Bubble, + counter::{BubbleExplodedCountThisFrame, BubbleSuckedCountThisFrame, KirbyHitCountThisFrame}, kirby::{Kirby, SuckArea}, sphere_collider::SphereCollider, }; @@ -55,7 +56,7 @@ impl DamageDealer { // Considerating ennemies are ponctual pub fn bubble_receive_damage( time: Res>, - + mut bubble_sucked: ResMut, mut enemy_query: Query<(&GlobalTransform, &mut Life), With>, kirby_query: Query<(&Kirby, &Children)>, @@ -74,6 +75,7 @@ pub fn bubble_receive_damage( for (enemy_transform, mut enemy_life) in &mut enemy_query { if suck_collider.point_inside(suck_transform.translation(), enemy_transform.translation()) { enemy_life.damage(suck_damage.damage_strength * time.delta_secs()); + bubble_sucked.increase(1); } } } @@ -82,14 +84,22 @@ pub fn bubble_receive_damage( // Considerating allies are ponctual pub fn kirby_receive_damage( - mut ally_query: Query<(&GlobalTransform, &mut Life), With>, - mut enemy_query: Query<(&GlobalTransform, &SphereCollider, &DamageDealer, &mut Life), With>, + mut bubble_exploded: ResMut, + mut kirby_hit: ResMut, + mut kirby_query: Query<(&GlobalTransform, &mut Life), (With, Without)>, + mut bubble_query: Query< + (&GlobalTransform, &SphereCollider, &DamageDealer, &mut Life), + (With, Without), + >, ) { - for (ally_transform, mut ally_life) in &mut ally_query { - for (enemy_transform, enemy_sphere_collider, enemy_damage_dealer, mut bubble_life) in &mut enemy_query { - if enemy_sphere_collider.point_inside(ally_transform.translation(), enemy_transform.translation()) { - ally_life.damage(enemy_damage_dealer.damage_strength); + for (kirby_transform, mut kirby_life) in &mut kirby_query { + for (bubble_transform, bubble_sphere_collider, bubble_damage_dealer, mut bubble_life) in &mut bubble_query { + if bubble_sphere_collider.point_inside(kirby_transform.translation(), bubble_transform.translation()) { + kirby_life.damage(bubble_damage_dealer.damage_strength); bubble_life.damage(1000000.0); // Bubble explode + // println!("{:?}", kirby_life.current_life) + bubble_exploded.increase(1); + kirby_hit.increase(1); } } } diff --git a/src/main.rs b/src/main.rs index f70878d..e6488b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,16 +3,21 @@ use bevy::prelude::*; use bubble::{bubble_move, bubble_spawn}; use camera::spawn_camera; use density_grid::{DensityGrid, density_grid_force, density_grid_update, init_density_object}; -use kirby::{kirby_actions, kirby_spawn}; use life::despawn_if_dead; +use life::{bubble_receive_damage, kirby_receive_damage}; use map::MapBounds; -use physics_body::integrate; +use physics_body::physics_integrate; -use crate::life::bubble_receive_damage; +use crate::bubble::BubblePlugin; +use crate::camera::MyCameraPlugin; +use crate::counter::CounterPlugin; +use crate::density_grid::DensityGridPlugin; +use crate::kirby::KirbyPlugin; mod animation; mod bubble; mod camera; +mod counter; mod density_grid; mod globals; mod kirby; @@ -24,19 +29,17 @@ mod sphere_collider; fn main() { App::new() .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) + .add_plugins(CounterPlugin) + .add_plugins(KirbyPlugin) + .add_plugins(DensityGridPlugin) + .add_plugins(BubblePlugin) + .add_plugins(MyCameraPlugin) .insert_resource(Time::::from_seconds(1.0 / 60.0)) .insert_resource(MapBounds { min: Vec2::ONE * -600.0, max: Vec2::ONE * 600.0 }) - .insert_resource(DensityGrid::new()) - .add_systems(Startup, spawn_camera) - .add_systems(Startup, kirby_spawn) - .add_systems(Startup, bubble_spawn) - .add_systems(PostStartup, init_density_object) .add_systems(Update, animate_sprite) - .add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain()) - .add_systems(FixedUpdate, kirby_actions) - .add_systems(FixedUpdate, bubble_move) .add_systems(FixedUpdate, bubble_receive_damage) + .add_systems(FixedUpdate, kirby_receive_damage) .add_systems(FixedPostUpdate, despawn_if_dead) - .add_systems(FixedPostUpdate, integrate) + .add_systems(FixedPostUpdate, physics_integrate) .run(); } diff --git a/src/physics_body.rs b/src/physics_body.rs index d14b757..ff80c1d 100644 --- a/src/physics_body.rs +++ b/src/physics_body.rs @@ -17,7 +17,11 @@ impl Default for PhysicsBody { } } -pub fn integrate(bounds: Res, mut query: Query<(&mut Transform, &mut PhysicsBody)>, time: Res>) { +pub fn physics_integrate( + bounds: Res, + mut query: Query<(&mut Transform, &mut PhysicsBody)>, + time: Res>, +) { for (mut transform, mut physicsbody) in &mut query { let force = physicsbody.force; let mass = physicsbody.mass;