Skip to main content

bonked2d/
object.rs

1//! Simple physics engine for the game
2
3/// Kinematic body
4pub mod kinematic_body;
5
6/// Static body
7pub mod static_body;
8
9/// Trigger area
10pub mod trigger_area;
11
12/// Hit result between solid objects
13pub mod contact;
14
15use super::Mask;
16use crate::{
17    object::{kinematic_body::KinematicBody, static_body::StaticBody},
18    world::aabb::Aabb,
19};
20use alloc::sync::Arc;
21use bvh_arena::VolumeHandle;
22use parry::{
23    math::{Isometry, Real, Vector},
24    query::{self, Contact, ShapeCastHit, ShapeCastOptions},
25    shape::Shape,
26};
27
28/// Mask where all bits are set to 1
29const MASK_ALL: Mask = Mask::MAX;
30
31/// Trait implemented for static and dynamic bodies
32pub trait Object {
33    type Payload;
34
35    /// Store the handle of this object after it has been added to the world
36    fn set_handle(&mut self, handle: VolumeHandle);
37
38    /// Unset the handle of this object
39    fn unset_handle(&mut self);
40
41    /// Access the handle of this object
42    fn handle(&self) -> Option<VolumeHandle>;
43
44    /// Access the shape assigned to this body
45    fn shape(&self) -> &dyn Shape;
46
47    /// Access the isometry of this shape
48    fn isometry(&self) -> &Isometry<Real>;
49
50    /// Create an Axis-Aligned Bounding Box for this body
51    fn aabb(&self) -> Aabb;
52
53    /// Access the payload defined on this object
54    fn payload(&self) -> &Self::Payload;
55
56    /// Access the payload defined on this object
57    fn payload_mut(&mut self) -> &mut Self::Payload;
58
59    /// Get the layer(s) this body belongs to
60    #[inline]
61    fn layer(&self) -> Mask {
62        MASK_ALL
63    }
64
65    /// Get the layers this body can interact with
66    #[inline]
67    fn mask(&self) -> Mask {
68        MASK_ALL
69    }
70
71    /// Get the velocity of the body (if it has one)
72    #[inline]
73    fn velocity(&self) -> Vector<Real> {
74        Vector::default()
75    }
76
77    /// Try to cast the object into a kinematic body
78    #[inline]
79    fn as_kinematic(&self) -> Option<&KinematicBody<Self::Payload>> {
80        None
81    }
82
83    /// Try to cast the object into a static body
84    #[inline]
85    fn as_static(&self) -> Option<&StaticBody<Self::Payload>> {
86        None
87    }
88}
89
90/// Common data shared between static and dynamic bodies
91struct CommonData<P> {
92    /// Handle of this body in the world
93    handle: Option<VolumeHandle>,
94
95    /// Collision shape used by this zone
96    shape: Arc<dyn Shape>,
97
98    /// Isometry of this body
99    isometry: Isometry<Real>,
100
101    /// Arbitrary payload
102    payload: P,
103}
104
105impl<P> CommonData<P> {
106    /// Create a new common data instance
107    #[inline]
108    pub fn new(shape: Arc<dyn Shape>, isometry: Isometry<Real>, payload: P) -> Self {
109        CommonData {
110            handle: None,
111            shape,
112            isometry,
113            payload,
114        }
115    }
116}
117
118impl<P> Object for CommonData<P> {
119    type Payload = P;
120
121    /// Store the handle of this object after it has been added to the world
122    #[inline]
123    fn set_handle(&mut self, handle: VolumeHandle) {
124        self.handle = Some(handle);
125    }
126
127    /// Unset the handle of this object
128    #[inline]
129    fn unset_handle(&mut self) {
130        self.handle = None;
131    }
132
133    /// Access the handle of this object
134    #[inline]
135    fn handle(&self) -> Option<VolumeHandle> {
136        self.handle
137    }
138
139    /// Access the shape assigned to this body
140    #[inline]
141    fn shape(&self) -> &dyn Shape {
142        self.shape.as_ref()
143    }
144
145    /// Access the isometry of this shape
146    #[inline]
147    fn isometry(&self) -> &Isometry<f32> {
148        &self.isometry
149    }
150
151    /// Build a generic AABB for this body
152    #[inline]
153    fn aabb(&self) -> Aabb {
154        Aabb::new(self.shape.compute_aabb(&self.isometry), MASK_ALL, MASK_ALL)
155    }
156
157    /// Access the payload defined on this object
158    #[inline]
159    fn payload(&self) -> &Self::Payload {
160        &self.payload
161    }
162
163    /// Access the payload defined on this object
164    #[inline]
165    fn payload_mut(&mut self) -> &mut Self::Payload {
166        &mut self.payload
167    }
168}
169
170/// Check if two objects intersects
171#[inline]
172pub fn intersects<A, B>(a: &A, b: &B) -> bool
173where
174    A: Object,
175    B: Object,
176{
177    query::intersection_test(a.isometry(), a.shape(), b.isometry(), b.shape()).unwrap_or(false)
178}
179
180/// Check if two objects are in contact
181#[inline]
182pub fn contacts<A, B>(a: &A, b: &B, prediction: Real) -> Option<Contact>
183where
184    A: Object,
185    B: Object,
186{
187    query::contact(a.isometry(), a.shape(), b.isometry(), b.shape(), prediction).unwrap_or(None)
188}
189
190/// Check if two objects will collide
191#[inline]
192pub fn collides<A, B>(a: &A, b: &B, options: ShapeCastOptions) -> Option<ShapeCastHit>
193where
194    A: Object,
195    B: Object,
196{
197    query::cast_shapes(
198        a.isometry(),
199        &a.velocity(),
200        a.shape(),
201        b.isometry(),
202        &b.velocity(),
203        b.shape(),
204        options,
205    )
206    .unwrap_or(None)
207}