bevy_tnua_physics_integration_layer/
spatial_ext.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use bevy::prelude::*;

use crate::math::{Float, Vector3};

/// Structured spatial queries.
///
/// Physics integration crates should define a [`SystemParam`](bevy::ecs::system::SystemParam) type
/// and implement this trait on it. The main Tnua crate (or third party crates) can define wrappers
/// (like `TnuaRadarLens`) that can utilize these queries to present helper methods for user code.
pub trait TnuaSpatialExt {
    /// The data required to answer queries on a collider.
    type ColliderData<'a>
    where
        Self: 'a;

    /// Get the [`ColliderData`](TnuaSpatialExt::ColliderData) from the sytem.
    ///
    /// Since the struct implementing `TnuaSpatialExt` is typically a `SystemParam`, it can use its
    /// fields to get that data from the ECS.
    fn fetch_collider_data(&self, entity: Entity) -> Option<Self::ColliderData<'_>>;

    /// Return the point on the collider that's closest to some external point.
    fn project_point(
        &self,
        point: Vector3,
        solid: bool,
        collider_data: &Self::ColliderData<'_>,
    ) -> TnuaPointProjectionResult;

    /// Cast a ray on the collider, returning the time-of-impact and the normal.
    fn cast_ray(
        &self,
        origin: Vector3,
        direction: Vector3,
        max_time_of_impact: Float,
        collider_data: &Self::ColliderData<'_>,
    ) -> Option<(Float, Vector3)>;

    /// Check if the physics engine is solving interaction between the two entities.
    ///
    /// If the physics engine is detecting the collision but does not apply forces according to it,
    /// this method should return `false`.
    fn can_interact(&self, entity1: Entity, entity2: Entity) -> bool;
}

#[derive(Debug, Copy, Clone)]
pub enum TnuaPointProjectionResult {
    Outside(Vector3),
    Inside(Vector3),
}

impl TnuaPointProjectionResult {
    pub fn get(&self) -> Vector3 {
        match self {
            TnuaPointProjectionResult::Outside(point) => *point,
            TnuaPointProjectionResult::Inside(point) => *point,
        }
    }

    pub fn outside(&self) -> Option<Vector3> {
        if let Self::Outside(point) = self {
            Some(*point)
        } else {
            None
        }
    }

    pub fn inside(&self) -> Option<Vector3> {
        if let Self::Inside(point) = self {
            Some(*point)
        } else {
            None
        }
    }
}