use std::{thread::panicking, time::Duration}; use bevy::{ecs::system::lifetimeless::SCommands, prelude::*}; use rand::distr::slice::Empty; use crate::{ core::{ bubble::{Bubble, bubble_spawn_wave}, collectible::{COLLECTABLE_SCALE, CollectableType, collectable_spawn}, game_state::{DispawnOnGameOver, EndGameEvent, EndGameReason, Resetable}, kirby::Kirby, life::Life, }, map::map::{BOTTOM, LEFT, RIGHT, TOP}, }; #[derive(Event)] pub struct NextWaveEvent; #[derive(Component)] #[require(DispawnOnGameOver)] pub struct NextWaveTimer { timer: Timer, } #[derive(Event)] struct NextWaveTimerTimeout; 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 { waves: Vec>, collectables: Vec>, pub current_wave: usize, } fn get_bubble_waves() -> BubbleWaves { let return_thing = 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), ], ], collectables: vec![ vec![], vec![(CollectableType::NewKirby, LEFT)], vec![(CollectableType::SpeedBoost, BOTTOM)], vec![(CollectableType::ShieldBoost, BOTTOM)], vec![], ], current_wave: 0, }; assert!(return_thing.waves.len() == return_thing.collectables.len()); return return_thing; } impl Resetable for BubbleWaves { fn reset(&mut self) { *self = get_bubble_waves(); } } #[derive(Resource, Default)] // Default is false pub struct EnnemyWaveLock(bool); impl Resetable for EnnemyWaveLock { fn reset(&mut self) { *self = EnnemyWaveLock::default() } } fn no_ennemy_left(bubble_query: Query<(), With>) -> bool { bubble_query.is_empty() } #[derive(Component)] #[require(Sprite, Transform, DispawnOnGameOver)] struct WarningSign; fn change_wave( mut lock: ResMut, bubble_wave: Res, mut commands: Commands, asset_server: Res, ) { // Beetwen moment where all ennemies are killed and NextWaveTimer trigger the spawn of the new ennemy // there is some time, and change_wave will be called every frame during this instance // that's why there is an ugly-ass lock if lock.0 { return; } lock.0 = true; let max_bubble_wave = bubble_wave.waves.len(); if bubble_wave.current_wave >= max_bubble_wave { commands.trigger(EndGameEvent { reason: EndGameReason::Victory }); return; } let current_bubble_wave = &bubble_wave.waves[bubble_wave.current_wave]; for bubble_splash in current_bubble_wave { commands.spawn(( WarningSign, Sprite::from_image(asset_server.load("sprites/warning.png")), Transform::from_translation(bubble_splash.center.extend(0.0)).with_scale(Vec3::splat(COLLECTABLE_SCALE)), )); } println!("change wave"); commands.trigger(NextWaveEvent); commands.spawn((NextWaveTimer { timer: Timer::new(Duration::from_secs(1), TimerMode::Once) },)); } fn next_wave_timer_system( next_wave_timer_query: Single<(&mut NextWaveTimer, Entity)>, time: Res