use std::time::{Duration, Instant};
use bevy::prelude::*;
use bevy_xpbd_2d::components::{AngularVelocity, LinearVelocity};
pub struct UndertakerPlugin;
impl Plugin for UndertakerPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<UndertakerConfig>()
.add_event::<Undertaken>()
.add_systems(Update, (undertaker_debug_line, update_mortals));
}
}
#[derive(Event)]
pub struct Undertaken {
position: Vec3,
}
#[derive(Resource)]
pub struct UndertakerConfig {
pub under_y: f32,
pub max_time_under: Duration,
}
impl Default for UndertakerConfig {
fn default() -> Self {
Self {
under_y: 0.0,
max_time_under: Duration::from_secs(1),
}
}
}
#[derive(Component, Default)]
pub struct Mortal {
pub respawn: Option<Vec3>,
instant_under: Option<Instant>,
}
impl Mortal {
pub fn respawnable(respawn: Vec3) -> Self {
Self {
respawn: Some(respawn),
..default()
}
}
}
#[allow(clippy::type_complexity)]
fn update_mortals(
mut query: Query<(
Entity,
&mut Mortal,
&mut Transform,
&GlobalTransform,
Option<&mut LinearVelocity>,
Option<&mut AngularVelocity>,
)>,
config: Res<UndertakerConfig>,
mut commands: Commands,
mut writer: EventWriter<Undertaken>,
) {
for (entity, mut mortality, mut transform, global_transform, lin_vel, ang_vel) in
query.iter_mut()
{
if global_transform.translation().y >= config.under_y {
mortality.instant_under = None;
} else {
let mortal_instant = mortality.instant_under.unwrap_or(Instant::now());
if mortal_instant.elapsed() > config.max_time_under {
if let Some(declared_respawn) = mortality.respawn {
let respawn_point = Vec3::new(
declared_respawn.x,
declared_respawn.y.max(config.under_y),
declared_respawn.z,
);
transform.translation = respawn_point;
if let Some(mut linear) = lin_vel {
linear.0 = Vec2::ZERO;
}
if let Some(mut angular) = ang_vel {
angular.0 = 0.;
}
writer.send(Undertaken {
position: global_transform.translation(),
});
mortality.instant_under = None;
} else {
commands.entity(entity).despawn_recursive();
}
} else {
mortality.instant_under = Some(mortal_instant);
}
}
}
}
fn undertaker_debug_line(mut gizmos: Gizmos, config: Res<UndertakerConfig>) {
gizmos.primitive_2d(
Plane2d::new(Vec2::Y),
Vec2::Y * config.under_y,
0.,
Color::ORANGE_RED,
);
}