collision_detection/
lib.rs

1#![deny(missing_docs)]
2
3/*!
4This crate defines an infrastructure to handle collision detection.
5
6It's based on the `collide` crate, so your colliders need need to implement the `Collider` trait.
7
8The `CollisionManager`, which can only contain one type of collider.
9When you want to use multiple colliders, you currently need to use trait objects or enums.
10
11Then you can add bodies and colliders to the manager. You should store their indices, which will be used when you modify or remove them.
12When you're done, you can compute the collisions, which you can use to update your objects.
13Before computing the collisions again, you should update your bodies and colliders.
14**/
15
16use array_linked_list::ArrayLinkedList;
17use collide::{Collider, CollisionInfo};
18use vector_space::VectorSpace;
19
20/// An object which might consist of multiple colliders.
21/// Collisions between multiple colliders of the same body are not checked.
22pub struct Body<C: Collider> {
23    /// All the colliders of the body.
24    pub colliders: Vec<C>,
25}
26
27impl<C: Collider> Body<C> {
28    /// Creates a new body.
29    pub fn new() -> Self {
30        Self {
31            colliders: Vec::new(),
32        }
33    }
34
35    /// Adds a collider to the body.
36    pub fn with_collider(mut self, collider: C) -> Self {
37        self.colliders.push(collider);
38        self
39    }
40}
41
42/// Represents the index of a static or dynamic inserted object.
43#[derive(Copy, Clone)]
44pub enum ObjectIndex<S, D> {
45    /// The index of the static object represented by the collider.
46    Static(S),
47    /// The index of the dynamic object represented by the body.
48    Dynamic(D),
49}
50
51/// The collision info with the index of the collider or body.
52pub struct IndexedCollisionInfo<V: VectorSpace, S, D> {
53    /// Index of the collider or body.
54    pub index: ObjectIndex<S, D>,
55    /// The actual collision info.
56    pub info: CollisionInfo<V>,
57}
58
59struct Static<C: Collider, I> {
60    collider: C,
61    index: I,
62}
63
64struct Dynamic<C: Collider, I> {
65    body: Body<C>,
66    index: I,
67}
68
69/// The collision manager, which manages collisions.
70/// Can contain multiple bodies and other colliders.
71/// Collisions between colliders are not checked.
72pub struct CollisionManager<C: Collider, S, D> {
73    bodies: ArrayLinkedList<Dynamic<C, D>>,
74    colliders: ArrayLinkedList<Static<C, S>>,
75}
76
77impl<C: Collider, S: Copy, D: Copy> CollisionManager<C, S, D> {
78    /// Creates a new collision manager.
79    pub fn new() -> Self {
80        Self {
81            bodies: ArrayLinkedList::new(),
82            colliders: ArrayLinkedList::new(),
83        }
84    }
85
86    /// Creates a new collision manager with the capacity of expected bodies specified.
87    pub fn with_capacity(capacity: usize) -> Self {
88        Self {
89            bodies: ArrayLinkedList::with_capacity(capacity),
90            colliders: ArrayLinkedList::new(),
91        }
92    }
93
94    /// Inserts a new collider and returns its index.
95    /// An object index needs to be specified.
96    pub fn insert_collider(&mut self, collider: C, index: S) -> usize {
97        self.colliders.push_back(Static { collider, index })
98    }
99
100    /// Inserts a new body and returns its index.
101    /// An object index needs to be specified.
102    pub fn insert_body(&mut self, body: Body<C>, index: D) -> usize {
103        self.bodies.push_back(Dynamic { body, index })
104    }
105
106    /// Replaces the existing collider at the specified index by a new collider.
107    pub fn replace_collider(&mut self, index: usize, collider: C) {
108        self.colliders[index].as_mut().unwrap().collider = collider;
109    }
110
111    /// Replaces the existing body at the specified index by a new body.
112    pub fn replace_body(&mut self, index: usize, body: Body<C>) {
113        self.bodies[index].as_mut().unwrap().body = body;
114    }
115
116    /// Removes an existing collider, so the index is usable for a new collect again.
117    pub fn remove_collider(&mut self, index: usize) {
118        self.colliders.remove(index);
119    }
120
121    /// Removes an existing body, so the index is usable for a new body again.
122    pub fn remove_body(&mut self, index: usize) {
123        self.bodies.remove(index);
124    }
125
126    /// Get the collider at the sepcified index.
127    pub fn collider(&self, index: usize) -> &C {
128        &self.colliders[index].as_ref().unwrap().collider
129    }
130
131    /// Get the collider at the sepcified index as mutable.
132    pub fn collider_mut(&mut self, index: usize) -> &mut C {
133        &mut self.colliders[index].as_mut().unwrap().collider
134    }
135
136    /// Get the body at the sepcified index.
137    pub fn body(&self, index: usize) -> &Body<C> {
138        &self.bodies[index].as_ref().unwrap().body
139    }
140
141    /// Get the body at the sepcified index as mutable.
142    pub fn body_mut(&mut self, index: usize) -> &mut Body<C> {
143        &mut self.bodies[index].as_mut().unwrap().body
144    }
145
146    /// Checks for a static collision with collider and returns the index.
147    pub fn find_static_collision(&self, collider: &C) -> Option<S> {
148        for collider_static in &self.colliders {
149            if collider.check_collision(&collider_static.collider) {
150                return Some(collider_static.index);
151            }
152        }
153        None
154    }
155
156    /// Checks for a dynamic collision with collider and returns the index.
157    pub fn find_dynamic_collision(&self, collider: &C) -> Option<D> {
158        for body_dynamic in &self.bodies {
159            for dynamic_collider in &body_dynamic.body.colliders {
160                if collider.check_collision(dynamic_collider) {
161                    return Some(body_dynamic.index);
162                }
163            }
164        }
165        None
166    }
167
168    /// Checks for any collision with collider and returns the index.
169    pub fn find_collision(&self, collider: &C) -> Option<ObjectIndex<S, D>> {
170        if let Some(index) = self.find_dynamic_collision(collider) {
171            Some(ObjectIndex::Dynamic(index))
172        } else if let Some(index) = self.find_static_collision(collider) {
173            Some(ObjectIndex::Static(index))
174        } else {
175            None
176        }
177    }
178
179    /// Computes the collisions between all colliders of a body with all other colliders.
180    /// Returns a list for each, which can be indexed by the specified index.
181    pub fn compute_collisions(
182        &self,
183    ) -> ArrayLinkedList<Vec<IndexedCollisionInfo<C::Vector, S, D>>> {
184        let mut result = ArrayLinkedList::with_capacity(self.bodies.capacity());
185        for body_index in self.bodies.indices() {
186            result.replace_front(body_index, Vec::new());
187        }
188        for (body_index, body_dynamic) in self.bodies.indexed() {
189            let infos = result[body_index].as_mut().unwrap();
190            // check static collisions
191            for collider_static in &self.colliders {
192                for body_collider in &body_dynamic.body.colliders {
193                    if let Some(info) = body_collider.collision_info(&collider_static.collider) {
194                        infos.push(IndexedCollisionInfo {
195                            index: ObjectIndex::Static(collider_static.index),
196                            info,
197                        });
198                    }
199                }
200            }
201            let infos = infos as *mut _;
202            // check dynamic collisions
203            for (other_index, other_dynamic) in self.bodies.indexed_after(body_index) {
204                let other_infos = result[other_index].as_mut().unwrap();
205                for dynamic_collider in &other_dynamic.body.colliders {
206                    for body_collider in &body_dynamic.body.colliders {
207                        if let Some(info) = body_collider.collision_info(dynamic_collider) {
208                            other_infos.push(IndexedCollisionInfo {
209                                index: ObjectIndex::Dynamic(body_dynamic.index),
210                                info: -info,
211                            });
212                            unsafe {
213                                std::mem::transmute::<
214                                    _,
215                                    &mut Vec<IndexedCollisionInfo<C::Vector, S, D>>,
216                                >(infos)
217                            }
218                            .push(IndexedCollisionInfo {
219                                index: ObjectIndex::Dynamic(other_dynamic.index),
220                                info,
221                            });
222                        }
223                    }
224                }
225            }
226        }
227        result
228    }
229}