bevy_tnua_physics_integration_layer/
spatial_ext.rs

1use bevy::prelude::*;
2
3use crate::math::{Float, Vector3};
4
5/// Structured spatial queries.
6///
7/// Physics integration crates should define a [`SystemParam`](bevy::ecs::system::SystemParam) type
8/// and implement this trait on it. The main Tnua crate (or third party crates) can define wrappers
9/// (like `TnuaRadarLens`) that can utilize these queries to present helper methods for user code.
10pub trait TnuaSpatialExt {
11    /// The data required to answer queries on a collider.
12    type ColliderData<'a>
13    where
14        Self: 'a;
15
16    /// Get the [`ColliderData`](TnuaSpatialExt::ColliderData) from the sytem.
17    ///
18    /// Since the struct implementing `TnuaSpatialExt` is typically a `SystemParam`, it can use its
19    /// fields to get that data from the ECS.
20    fn fetch_collider_data(&self, entity: Entity) -> Option<Self::ColliderData<'_>>;
21
22    /// Return the point on the collider that's closest to some external point.
23    fn project_point(
24        &self,
25        point: Vector3,
26        solid: bool,
27        collider_data: &Self::ColliderData<'_>,
28    ) -> TnuaPointProjectionResult;
29
30    /// Cast a ray on the collider, returning the time-of-impact and the normal.
31    fn cast_ray(
32        &self,
33        origin: Vector3,
34        direction: Vector3,
35        max_time_of_impact: Float,
36        collider_data: &Self::ColliderData<'_>,
37    ) -> Option<(Float, Vector3)>;
38
39    /// Check if the physics engine is solving interaction between the two entities.
40    ///
41    /// If the physics engine is detecting the collision but does not apply forces according to it,
42    /// this method should return `false`.
43    fn can_interact(&self, entity1: Entity, entity2: Entity) -> bool;
44}
45
46#[derive(Debug, Copy, Clone)]
47pub enum TnuaPointProjectionResult {
48    Outside(Vector3),
49    Inside(Vector3),
50}
51
52impl TnuaPointProjectionResult {
53    pub fn get(&self) -> Vector3 {
54        match self {
55            TnuaPointProjectionResult::Outside(point) => *point,
56            TnuaPointProjectionResult::Inside(point) => *point,
57        }
58    }
59
60    pub fn outside(&self) -> Option<Vector3> {
61        if let Self::Outside(point) = self {
62            Some(*point)
63        } else {
64            None
65        }
66    }
67
68    pub fn inside(&self) -> Option<Vector3> {
69        if let Self::Inside(point) = self {
70            Some(*point)
71        } else {
72            None
73        }
74    }
75}