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}