use std::ops::RangeInclusive;
use avian3d::{math::Scalar, prelude::*};
use crate::{
interaction::{HoldError, ShadowParams},
prelude::*,
};
pub(super) mod prelude {
pub use super::{
AvianPickupActor, AvianPickupActorHoldConfig, AvianPickupActorPullConfig,
AvianPickupActorState, AvianPickupActorThrowConfig,
};
}
pub(super) fn plugin(app: &mut App) {
app.register_type::<(AvianPickupActor, AvianPickupActorState)>();
}
#[derive(Debug, Component, Clone, PartialEq, Reflect)]
#[reflect(Debug, Component, Default, PartialEq)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
#[require(AvianPickupActorState, Cooldown, HoldError, ShadowParams)]
pub struct AvianPickupActor {
pub prop_filter: SpatialQueryFilter,
pub obstacle_filter: SpatialQueryFilter,
pub actor_filter: SpatialQueryFilter,
pub interaction_distance: Scalar,
pub interaction_cone: f32,
pub pull: AvianPickupActorPullConfig,
pub hold: AvianPickupActorHoldConfig,
pub throw: AvianPickupActorThrowConfig,
}
#[derive(Debug, Clone, PartialEq, Reflect)]
#[reflect(Debug, Default, PartialEq)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub struct AvianPickupActorPullConfig {
pub impulse: Scalar,
pub max_prop_mass: Scalar,
}
impl Default for AvianPickupActorPullConfig {
fn default() -> Self {
Self {
impulse: 100.0,
max_prop_mass: 35.0,
}
}
}
#[derive(Debug, Clone, PartialEq, Reflect)]
#[reflect(Debug, Default, PartialEq)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub struct AvianPickupActorHoldConfig {
pub distance_to_allow_holding: Scalar,
pub min_distance: Scalar,
pub linear_velocity_easing: Scalar,
pub angular_velocity_easing: Scalar,
pub pitch_range: RangeInclusive<f32>,
pub preferred_distance: Scalar,
pub temporary_prop_mass: Scalar,
}
impl Default for AvianPickupActorHoldConfig {
fn default() -> Self {
Self {
distance_to_allow_holding: 3.0,
min_distance: 0.2,
linear_velocity_easing: 1.0,
angular_velocity_easing: 1.6,
pitch_range: (-75.0_f32).to_radians()..=75.0_f32.to_radians(),
preferred_distance: 0.6,
temporary_prop_mass: 1.0,
}
}
}
#[derive(Debug, Clone, PartialEq, Reflect)]
#[reflect(Debug, Default, PartialEq)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub struct AvianPickupActorThrowConfig {
pub cutoff_mass_for_slowdown: Scalar,
pub linear_speed_range: RangeInclusive<Scalar>,
pub angular_speed_range: RangeInclusive<Scalar>,
}
impl Default for AvianPickupActorThrowConfig {
fn default() -> Self {
Self {
cutoff_mass_for_slowdown: 20.0,
linear_speed_range: 0.0..=5.0,
angular_speed_range: 0.0..=1.0,
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Component, Default, Reflect)]
#[reflect(Debug, Component, PartialEq, Hash, Default)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub enum AvianPickupActorState {
#[default]
Idle,
Pulling(Entity),
Holding(Entity),
}
impl AvianPickupActorState {
pub fn is_idle(self) -> bool {
matches!(self, AvianPickupActorState::Idle)
}
pub fn is_pulling(self) -> bool {
matches!(self, AvianPickupActorState::Pulling { .. })
}
pub fn is_holding(self) -> bool {
matches!(self, AvianPickupActorState::Holding { .. })
}
}
impl Default for AvianPickupActor {
fn default() -> Self {
Self {
prop_filter: default(),
obstacle_filter: default(),
actor_filter: default(),
interaction_distance: 5.0,
interaction_cone: 0.97,
pull: default(),
hold: default(),
throw: default(),
}
}
}