waves
All checks were successful
Build Bevy Game (Linux + Windows) / build-windows (push) Successful in 18m50s
Build Bevy Game (Linux + Windows) / build-linux (push) Successful in 18m38s

This commit is contained in:
Crizomb 2026-01-04 00:25:35 +01:00
parent 751d8097d2
commit 4b9101ad2c
7 changed files with 143 additions and 29 deletions

View file

@ -4,11 +4,12 @@ use bevy::prelude::*;
use rand::Rng; use rand::Rng;
use crate::{ use crate::{
core::kirby::Kirby, core::{
core::life::{DamageDealer, Life}, kirby::Kirby,
physics::density_grid::DensityObject, life::{DamageDealer, Life},
physics::physics_body::PhysicsBody, wave::BubbleSplash,
physics::sphere_collider::SphereCollider, },
physics::{density_grid::DensityObject, physics_body::PhysicsBody, sphere_collider::SphereCollider},
}; };
#[derive(Component)] #[derive(Component)]
@ -17,23 +18,29 @@ pub struct Bubble {
move_force: f32, move_force: f32,
} }
pub fn bubble_spawn(mut commands: Commands, asset_server: Res<AssetServer>) { // pub fn bubble_spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
// bubble_spawn_wave(&mut commands, &asset_server, 1000);
// }
pub fn bubble_spawn_wave(commands: &mut Commands, asset_server: &Res<AssetServer>, bubble_splashes: &[BubbleSplash]) {
let texture: Handle<Image> = asset_server.load("sprites/bubble.png"); let texture: Handle<Image> = asset_server.load("sprites/bubble.png");
let mut rng = rand::rng(); let mut rng = rand::rng();
for _ in 0..50 { for BubbleSplash { bubble_type, center, radius, nb_bubbles } in bubble_splashes {
let angle = rng.random_range(0.0..TAU); for _ in 0..*nb_bubbles {
let pos = Vec2::from_angle(angle) * 500.0; let angle = rng.random_range(0.0..TAU);
let pos = center + Vec2::from_angle(angle) * radius;
commands.spawn(( commands.spawn((
Bubble { move_force: 3000.0 }, Bubble { move_force: bubble_type.move_force },
Sprite { image: texture.clone(), ..default() }, Sprite { image: texture.clone(), color: bubble_type.color, ..default() },
PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 }, 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)), Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(1.0)),
Life::new(10.0), Life::new(bubble_type.max_life),
DamageDealer::new(0.5), DamageDealer::new(0.5),
SphereCollider::new(20.0), SphereCollider::new(20.0),
)); ));
}
} }
} }
@ -62,6 +69,6 @@ pub struct BubblePlugin;
impl Plugin for BubblePlugin { impl Plugin for BubblePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Startup, bubble_spawn).add_systems(FixedUpdate, bubble_move); app.add_systems(FixedUpdate, bubble_move);
} }
} }

View file

@ -1,10 +1,6 @@
use std::path::Path; use std::path::Path;
use std::time::Duration; use std::time::Duration;
#[derive(Component)]
struct kirbyTimer(Timer);
use crate::core::counter::BubbleKilledTotalCount;
use crate::core::kirby::{Kirby, kirby_spawn}; use crate::core::kirby::{Kirby, kirby_spawn};
use crate::physics::sphere_collider::SphereCollider; use crate::physics::sphere_collider::SphereCollider;
use bevy::prelude::*; use bevy::prelude::*;
@ -80,9 +76,10 @@ fn shield_boost(kirby: &mut Kirby) {
} }
fn new_kirby(kirby_pos: Vec3, commands: &mut Commands) { fn new_kirby(kirby_pos: Vec3, commands: &mut Commands) {
commands.spawn( commands.spawn(KirbySpawnHandler {
(KirbySpawnHandler { timer: Timer::new(KIRBY_SPAWN_TIMER_DURATION, TimerMode::Once), position: kirby_pos }), timer: Timer::new(KIRBY_SPAWN_TIMER_DURATION, TimerMode::Once),
); position: kirby_pos,
});
} }
#[derive(Component)] #[derive(Component)]
@ -92,7 +89,7 @@ struct KirbySpawnHandler {
} }
// After player get new_kirby item, it should spawn a new_kirby after a certain time // 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, mut commands: Commands,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>, mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,

View file

@ -61,7 +61,7 @@ pub fn kirby_spawn(
Transform::from_xyz(40.0, 0.0, 0.0), Transform::from_xyz(40.0, 0.0, 0.0),
SuckArea, SuckArea,
SphereCollider::new(80.0), SphereCollider::new(80.0),
DamageDealer::new(10000.0), DamageDealer::new(100.0),
)); ));
} }

View file

@ -3,3 +3,4 @@ pub mod collectible;
pub mod counter; pub mod counter;
pub mod kirby; pub mod kirby;
pub mod life; pub mod life;
pub mod wave;

97
src/core/wave.rs Normal file
View file

@ -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<Vec<BubbleSplash>>,
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<Bubble>>) -> bool {
bubble_query.is_empty()
}
fn change_wave(mut bubble_wave: ResMut<BubbleWaves>, mut commands: Commands, asset_server: Res<AssetServer>) {
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));
}
}

View file

@ -14,12 +14,15 @@ use core::life::{bubble_receive_damage, despawn_if_dead, kirby_receive_damage};
mod map; mod map;
use map::map::MAP_SIZE; use map::map::MAP_SIZE;
use map::map::MAP_WIDTH;
use map::map::MapBounds; use map::map::MapBounds;
mod juice; mod juice;
use juice::animation::animate_sprite; use juice::animation::animate_sprite;
use juice::camera::MyCameraPlugin; use juice::camera::MyCameraPlugin;
use crate::core::wave::WavePlugin;
fn main() { fn main() {
App::new() App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()).set(WindowPlugin { .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()).set(WindowPlugin {
@ -37,8 +40,9 @@ fn main() {
.add_plugins(BubblePlugin) .add_plugins(BubblePlugin)
.add_plugins(MyCameraPlugin) .add_plugins(MyCameraPlugin)
.add_plugins(CollectablePlugin) .add_plugins(CollectablePlugin)
.add_plugins(WavePlugin)
.insert_resource(Time::<Fixed>::from_seconds(1.0 / 60.0)) .insert_resource(Time::<Fixed>::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(Update, animate_sprite)
.add_systems(FixedUpdate, bubble_receive_damage) .add_systems(FixedUpdate, bubble_receive_damage)
.add_systems(FixedUpdate, kirby_receive_damage) .add_systems(FixedUpdate, kirby_receive_damage)

View file

@ -1,6 +1,14 @@
use bevy::prelude::*; use bevy::prelude::*;
pub const MAP_SIZE: u32 = 1000; 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)] #[derive(Resource)]
pub struct MapBounds { pub struct MapBounds {