use bevy::{
math::Vec3,
prelude::{Component, Entity},
};
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use crate::{ErasedParticleSystem, ExpirationState, Particle, ParticleBuffer, ParticleSystem};
#[derive(Debug, Clone, Copy)]
pub enum ParticleEventType {
Explode,
Fizzle,
Collide,
}
impl From<ExpirationState> for ParticleEventType {
fn from(value: ExpirationState) -> Self {
match value {
ExpirationState::None => panic!(),
ExpirationState::Fizzle => ParticleEventType::Fizzle,
ExpirationState::Explode => ParticleEventType::Explode,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParticleEvent {
pub event: ParticleEventType,
pub seed: f32,
pub lifetime: f32,
pub position: Vec3,
pub tangent: Vec3,
}
#[derive(Debug, Component, Clone, Copy)]
pub struct ParticleParent(pub Entity);
#[derive(Debug, Component, Default)]
pub struct ParticleEventBuffer(Vec<ParticleEvent>);
impl Deref for ParticleEventBuffer {
type Target = Vec<ParticleEvent>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ParticleEventBuffer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub trait SubParticleSystem: ParticleSystem {
type Parent: Particle;
fn spawn_step_sub(&mut self, parent: &mut Self::Parent, dt: f32) -> usize;
fn into_sub_particle(parent: &Self::Parent, seed: f32) -> Self::Particle;
}
pub trait ErasedSubParticleSystem: ErasedParticleSystem {
fn spawn_from_parent(
&mut self,
dt: f32,
buffer: &mut ParticleBuffer,
parent: &mut ParticleBuffer,
);
}
impl<T> ErasedSubParticleSystem for T
where
T: SubParticleSystem + ErasedParticleSystem,
{
fn spawn_from_parent(
&mut self,
dt: f32,
buffer: &mut ParticleBuffer,
parent: &mut ParticleBuffer,
) {
for parent in parent.get_mut::<T::Parent>() {
if parent.is_expired() {
continue;
}
let num = self.spawn_step_sub(parent, dt);
buffer.extend(
(0..num)
.map(|_| self.rng())
.map(|seed| Self::into_sub_particle(parent, seed)),
)
}
}
}
impl Debug for dyn ErasedSubParticleSystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_debug().fmt(f)
}
}
pub trait EventParticleSystem: ParticleSystem {
fn spawn_on_event(&mut self, parent: &ParticleEvent) -> usize;
fn into_sub_particle(parent: &ParticleEvent, seed: f32) -> Self::Particle;
}
pub trait ErasedEventParticleSystem: ErasedParticleSystem {
fn spawn_on_event(&mut self, buffer: &mut ParticleBuffer, parent: &ParticleEventBuffer);
}
impl<T> ErasedEventParticleSystem for T
where
T: EventParticleSystem + ErasedParticleSystem,
{
fn spawn_on_event(&mut self, buffer: &mut ParticleBuffer, parent: &ParticleEventBuffer) {
for event in parent.iter() {
let num = self.spawn_on_event(event);
buffer.extend(
(0..num)
.map(|_| self.rng())
.map(|seed| Self::into_sub_particle(event, seed)),
)
}
}
}
impl Debug for dyn ErasedEventParticleSystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_debug().fmt(f)
}
}