215 lines
6.4 KiB
Rust
215 lines
6.4 KiB
Rust
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<Vec<BubbleSplash>>,
|
|
collectables: Vec<Vec<(CollectableType, Vec2)>>,
|
|
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<Bubble>>) -> bool {
|
|
bubble_query.is_empty()
|
|
}
|
|
|
|
#[derive(Component)]
|
|
#[require(Sprite, Transform, DispawnOnGameOver)]
|
|
struct WarningSign;
|
|
|
|
fn change_wave(
|
|
mut lock: ResMut<EnnemyWaveLock>,
|
|
bubble_wave: Res<BubbleWaves>,
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
) {
|
|
// 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<Time>,
|
|
mut commands: Commands,
|
|
) {
|
|
let (mut next_wave_timer, timer_id) = next_wave_timer_query.into_inner();
|
|
next_wave_timer.timer.tick(time.delta());
|
|
if next_wave_timer.timer.is_finished() {
|
|
commands.trigger(NextWaveTimerTimeout);
|
|
commands.entity(timer_id).despawn();
|
|
}
|
|
}
|
|
|
|
fn delete_warning_sign(_: On<NextWaveTimerTimeout>, mut commands: Commands, query: Query<Entity, With<WarningSign>>) {
|
|
for entity in query {
|
|
commands.entity(entity).despawn();
|
|
}
|
|
}
|
|
|
|
fn spawn_wave_ennemy(
|
|
_: On<NextWaveTimerTimeout>,
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut bubble_wave: ResMut<BubbleWaves>,
|
|
mut lock: ResMut<EnnemyWaveLock>,
|
|
) {
|
|
let wave = &bubble_wave.waves[bubble_wave.current_wave];
|
|
let collectables = &bubble_wave.collectables[bubble_wave.current_wave];
|
|
|
|
bubble_spawn_wave(&mut commands, &asset_server, wave.as_slice());
|
|
for (collectable_type, collectable_pos) in collectables {
|
|
collectable_spawn(&mut commands, &asset_server, *collectable_type, *collectable_pos);
|
|
}
|
|
bubble_wave.current_wave += 1;
|
|
lock.0 = false; // Release lock, ennemy wave is spawnned
|
|
}
|
|
|
|
fn heal_kirby(query: Query<&mut Life, With<Kirby>>) {
|
|
for mut kirby_life in query {
|
|
kirby_life.heal(f32::MAX);
|
|
}
|
|
}
|
|
|
|
pub struct WavePlugin;
|
|
|
|
impl Plugin for WavePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.insert_resource(get_bubble_waves())
|
|
.insert_resource(EnnemyWaveLock::default())
|
|
.add_systems(Update, (change_wave, heal_kirby).run_if(no_ennemy_left))
|
|
.add_systems(Update, next_wave_timer_system)
|
|
.add_observer(spawn_wave_ennemy)
|
|
.add_observer(delete_warning_sign);
|
|
}
|
|
}
|