From 4b9101ad2cd54553d7771f5b832fdd9f7793c3d1 Mon Sep 17 00:00:00 2001 From: Crizomb Date: Sun, 4 Jan 2026 00:25:35 +0100 Subject: [PATCH] waves --- src/core/bubble.rs | 45 +++++++++++-------- src/core/collectible.rs | 13 +++--- src/core/kirby.rs | 2 +- src/core/mod.rs | 1 + src/core/wave.rs | 97 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 6 ++- src/map/map.rs | 8 ++++ 7 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 src/core/wave.rs diff --git a/src/core/bubble.rs b/src/core/bubble.rs index 62e2903..44f3724 100644 --- a/src/core/bubble.rs +++ b/src/core/bubble.rs @@ -4,11 +4,12 @@ use bevy::prelude::*; use rand::Rng; use crate::{ - core::kirby::Kirby, - core::life::{DamageDealer, Life}, - physics::density_grid::DensityObject, - physics::physics_body::PhysicsBody, - physics::sphere_collider::SphereCollider, + core::{ + kirby::Kirby, + life::{DamageDealer, Life}, + wave::BubbleSplash, + }, + physics::{density_grid::DensityObject, physics_body::PhysicsBody, sphere_collider::SphereCollider}, }; #[derive(Component)] @@ -17,23 +18,29 @@ pub struct Bubble { move_force: f32, } -pub fn bubble_spawn(mut commands: Commands, asset_server: Res) { +// pub fn bubble_spawn(mut commands: Commands, asset_server: Res) { +// bubble_spawn_wave(&mut commands, &asset_server, 1000); +// } + +pub fn bubble_spawn_wave(commands: &mut Commands, asset_server: &Res, bubble_splashes: &[BubbleSplash]) { let texture: Handle = asset_server.load("sprites/bubble.png"); let mut rng = rand::rng(); - for _ in 0..50 { - let angle = rng.random_range(0.0..TAU); - let pos = Vec2::from_angle(angle) * 500.0; + for BubbleSplash { bubble_type, center, radius, nb_bubbles } in bubble_splashes { + for _ in 0..*nb_bubbles { + let angle = rng.random_range(0.0..TAU); + let pos = center + Vec2::from_angle(angle) * radius; - commands.spawn(( - Bubble { move_force: 3000.0 }, - Sprite { image: texture.clone(), ..default() }, - 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), - )); + commands.spawn(( + Bubble { move_force: bubble_type.move_force }, + Sprite { image: texture.clone(), color: bubble_type.color, ..default() }, + 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(bubble_type.max_life), + DamageDealer::new(0.5), + SphereCollider::new(20.0), + )); + } } } @@ -62,6 +69,6 @@ pub struct BubblePlugin; impl Plugin for BubblePlugin { fn build(&self, app: &mut App) { - app.add_systems(Startup, bubble_spawn).add_systems(FixedUpdate, bubble_move); + app.add_systems(FixedUpdate, bubble_move); } } diff --git a/src/core/collectible.rs b/src/core/collectible.rs index c69a86b..3c40553 100644 --- a/src/core/collectible.rs +++ b/src/core/collectible.rs @@ -1,10 +1,6 @@ use std::path::Path; use std::time::Duration; -#[derive(Component)] -struct kirbyTimer(Timer); - -use crate::core::counter::BubbleKilledTotalCount; use crate::core::kirby::{Kirby, kirby_spawn}; use crate::physics::sphere_collider::SphereCollider; use bevy::prelude::*; @@ -80,9 +76,10 @@ fn shield_boost(kirby: &mut Kirby) { } fn new_kirby(kirby_pos: Vec3, commands: &mut Commands) { - commands.spawn( - (KirbySpawnHandler { timer: Timer::new(KIRBY_SPAWN_TIMER_DURATION, TimerMode::Once), position: kirby_pos }), - ); + commands.spawn(KirbySpawnHandler { + timer: Timer::new(KIRBY_SPAWN_TIMER_DURATION, TimerMode::Once), + position: kirby_pos, + }); } #[derive(Component)] @@ -92,7 +89,7 @@ struct KirbySpawnHandler { } // After player get new_kirby item, it should spawn a new_kirby after a certain time -pub fn kirby_spawn_timer( +fn kirby_spawn_timer( mut commands: Commands, asset_server: Res, mut texture_atlas_layouts: ResMut>, diff --git a/src/core/kirby.rs b/src/core/kirby.rs index 4bc1f64..bf63599 100644 --- a/src/core/kirby.rs +++ b/src/core/kirby.rs @@ -61,7 +61,7 @@ pub fn kirby_spawn( Transform::from_xyz(40.0, 0.0, 0.0), SuckArea, SphereCollider::new(80.0), - DamageDealer::new(10000.0), + DamageDealer::new(100.0), )); } diff --git a/src/core/mod.rs b/src/core/mod.rs index 31a2633..b30d8d8 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -3,3 +3,4 @@ pub mod collectible; pub mod counter; pub mod kirby; pub mod life; +pub mod wave; diff --git a/src/core/wave.rs b/src/core/wave.rs new file mode 100644 index 0000000..01def64 --- /dev/null +++ b/src/core/wave.rs @@ -0,0 +1,97 @@ +use std::thread::panicking; + +use bevy::prelude::*; +use rand::distr::slice::Empty; + +use crate::{ + core::bubble::{Bubble, bubble_spawn_wave}, + map::map::{BOTTOM, LEFT, RIGHT, TOP}, +}; + +pub struct BubbleType { + pub color: Color, + pub move_force: f32, + pub max_life: f32, +} + +pub struct BubbleSplash { + pub bubble_type: BubbleType, + pub center: Vec2, + pub radius: f32, + pub nb_bubbles: u32, +} + +impl BubbleSplash { + fn new(bubble_type: BubbleType, center: Vec2, radius: f32, nb_bubbles: u32) -> Self { + BubbleSplash { bubble_type, center, radius, nb_bubbles } + } +} + +const BASE_MOVE_FORCE: f32 = 3000.0; +const BASE_LIFE: f32 = 10.0; + +const NORMAL_BUBBLE: BubbleType = BubbleType { + color: Color::linear_rgb(1.0, 1.0, 1.0), + move_force: BASE_MOVE_FORCE * 1.0, + max_life: BASE_LIFE * 1.0, +}; + +const RED_BUBBLE: BubbleType = BubbleType { + color: Color::linear_rgb(1.0, 0.0, 0.0), + move_force: BASE_MOVE_FORCE * 2.0, + max_life: BASE_LIFE * 0.5, +}; + +const GREEN_BUBBLE: BubbleType = BubbleType { + color: Color::linear_rgb(1.0, 0.0, 0.0), + move_force: BASE_MOVE_FORCE * 0.5, + max_life: BASE_LIFE * 2.0, +}; + +#[derive(Resource)] +pub struct BubbleWaves { + pub waves: Vec>, + pub current_wave: usize, +} + +fn get_bubble_waves() -> BubbleWaves { + BubbleWaves { + waves: vec![ + vec![BubbleSplash::new(NORMAL_BUBBLE, RIGHT, 10.0, 10)], + vec![BubbleSplash::new(NORMAL_BUBBLE, RIGHT, 10.0, 10), BubbleSplash::new(NORMAL_BUBBLE, TOP, 10.0, 10)], + vec![BubbleSplash::new(NORMAL_BUBBLE, RIGHT, 10.0, 100), BubbleSplash::new(NORMAL_BUBBLE, TOP, 10.0, 100)], + vec![ + BubbleSplash::new(NORMAL_BUBBLE, RIGHT, 10.0, 100), + BubbleSplash::new(NORMAL_BUBBLE, TOP, 10.0, 100), + BubbleSplash::new(RED_BUBBLE, BOTTOM, 10.0, 20), + ], + vec![ + BubbleSplash::new(NORMAL_BUBBLE, RIGHT, 10.0, 200), + BubbleSplash::new(RED_BUBBLE, RIGHT, 10.0, 100), + BubbleSplash::new(RED_BUBBLE, LEFT, 10.0, 100), + ], + ], + current_wave: 0, + } +} + +fn no_ennemy_left(bubble_query: Query<(), With>) -> bool { + bubble_query.is_empty() +} + +fn change_wave(mut bubble_wave: ResMut, mut commands: Commands, asset_server: Res) { + let max_bubble_wave = bubble_wave.waves.len(); + bubble_wave.current_wave += 1; + if bubble_wave.current_wave >= max_bubble_wave { + panic!("GG you win"); + } + bubble_spawn_wave(&mut commands, &asset_server, bubble_wave.waves[bubble_wave.current_wave].as_slice()); +} + +pub struct WavePlugin; + +impl Plugin for WavePlugin { + fn build(&self, app: &mut App) { + app.insert_resource(get_bubble_waves()).add_systems(Update, change_wave.run_if(no_ennemy_left)); + } +} diff --git a/src/main.rs b/src/main.rs index 065ffa0..cb36c77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,12 +14,15 @@ use core::life::{bubble_receive_damage, despawn_if_dead, kirby_receive_damage}; mod map; use map::map::MAP_SIZE; +use map::map::MAP_WIDTH; use map::map::MapBounds; mod juice; use juice::animation::animate_sprite; use juice::camera::MyCameraPlugin; +use crate::core::wave::WavePlugin; + fn main() { App::new() .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()).set(WindowPlugin { @@ -37,8 +40,9 @@ fn main() { .add_plugins(BubblePlugin) .add_plugins(MyCameraPlugin) .add_plugins(CollectablePlugin) + .add_plugins(WavePlugin) .insert_resource(Time::::from_seconds(1.0 / 60.0)) - .insert_resource(MapBounds { min: -Vec2::ONE * MAP_SIZE as f32 / 2.0, max: Vec2::ONE * MAP_SIZE as f32 / 2.0 }) + .insert_resource(MapBounds { min: -Vec2::ONE * MAP_WIDTH as f32, max: Vec2::ONE * MAP_WIDTH as f32 }) .add_systems(Update, animate_sprite) .add_systems(FixedUpdate, bubble_receive_damage) .add_systems(FixedUpdate, kirby_receive_damage) diff --git a/src/map/map.rs b/src/map/map.rs index f8f5a4b..0432ae7 100644 --- a/src/map/map.rs +++ b/src/map/map.rs @@ -1,6 +1,14 @@ use bevy::prelude::*; pub const MAP_SIZE: u32 = 1000; +pub const MAP_WIDTH: u32 = MAP_SIZE / 2; + +pub const NEAR_LIMIT: f32 = (MAP_WIDTH as f32) * 0.8; + +pub const RIGHT: Vec2 = Vec2::new(NEAR_LIMIT, 0.0); +pub const LEFT: Vec2 = Vec2::new(-NEAR_LIMIT, 0.0); +pub const TOP: Vec2 = Vec2::new(0.0, NEAR_LIMIT); +pub const BOTTOM: Vec2 = Vec2::new(0.0, -NEAR_LIMIT); #[derive(Resource)] pub struct MapBounds {