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 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.
13You can either compute the collisions between all objects internally or between this object with a different layer.
14Before computing the collisions again, you should update your colliders, for example if the position of the object changed.
15**/
16
17use array_linked_list::ArrayLinkedList;
18use collide::{Collider, CollisionInfo};
19use vector_space::VectorSpace;
20
21/// The collision info with the index of the other collider.
22pub struct IndexedCollisionInfo<V: VectorSpace, I> {
23    /// Index of the object.
24    pub index: I,
25    /// The actual collision info.
26    pub info: CollisionInfo<V>,
27}
28
29struct Indexed<C: Collider, I> {
30    index: I,
31    collider: C,
32}
33
34/// The collision manager, which manages collisions.
35/// Can contain multiple colliders.
36pub struct CollisionManager<C: Collider, I> {
37    colliders: ArrayLinkedList<Indexed<C, I>>,
38}
39
40impl<C: Collider, I: Copy> Default for CollisionManager<C, I> {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46impl<C: Collider, I: Copy> CollisionManager<C, I> {
47    /// Creates a new collision manager.
48    pub fn new() -> Self {
49        Self {
50            colliders: ArrayLinkedList::new(),
51        }
52    }
53
54    /// Creates a new collision manager with the capacity of expected colliders specified.
55    pub fn with_capacity(capacity: usize) -> Self {
56        Self {
57            colliders: ArrayLinkedList::with_capacity(capacity),
58        }
59    }
60
61    /// Inserts a new collider and returns its index.
62    /// An object index needs to be specified.
63    pub fn insert_collider(&mut self, collider: C, index: I) -> usize {
64        self.colliders.push_back(Indexed { index, collider })
65    }
66
67    /// Replaces the existing collider at the specified index by a new collider.
68    pub fn replace_collider(&mut self, index: usize, collider: C) {
69        self.colliders[index].as_mut().unwrap().collider = collider;
70    }
71
72    /// Removes an existing collider, so the index is usable for a new collect again.
73    pub fn remove_collider(&mut self, index: usize) {
74        self.colliders.remove(index);
75    }
76
77    /// Get the collider at the sepcified index.
78    pub fn collider(&self, index: usize) -> &C {
79        &self.colliders[index].as_ref().unwrap().collider
80    }
81
82    /// Get the collider at the sepcified index as mutable.
83    pub fn collider_mut(&mut self, index: usize) -> &mut C {
84        &mut self.colliders[index].as_mut().unwrap().collider
85    }
86
87    /// Checks if theer is a collision at a specific position.
88    pub fn check_collision(&self, check_collider: &C) -> bool {
89        for collider in &self.colliders {
90            if check_collider.check_collision(&collider.collider) {
91                return true;
92            }
93        }
94        false
95    }
96
97    /// Checks for a collision with collider and returns some index if found.
98    pub fn find_collision(&self, check_collider: &C) -> Option<I> {
99        for collider in &self.colliders {
100            if check_collider.check_collision(&collider.collider) {
101                return Some(collider.index);
102            }
103        }
104        None
105    }
106
107    /// Finds all collisions with colliders and returns their indices.
108    pub fn find_collisions(&self, check_collider: &C) -> Vec<I> {
109        let mut result = Vec::new();
110        for collider in &self.colliders {
111            if check_collider.check_collision(&collider.collider) {
112                result.push(collider.index);
113            }
114        }
115        result
116    }
117
118    /// Computes the internal collisions between all colliders.
119    /// Returns a list for each, which can be indexed by the specified index.
120    pub fn compute_inner_collisions(
121        &self,
122    ) -> ArrayLinkedList<Vec<IndexedCollisionInfo<C::Vector, I>>> {
123        let mut result = ArrayLinkedList::with_capacity(self.colliders.capacity());
124        for collider_index in self.colliders.indices() {
125            result.replace_front(collider_index, Vec::new());
126        }
127        for (collider_index, indexed_collider) in self.colliders.indexed() {
128            let infos = result[collider_index].as_mut().unwrap() as *mut Vec<_>;
129            // check dynamic collisions
130            for (other_index, other_dynamic) in self.colliders.indexed_after(collider_index) {
131                let dynamic_collider = &other_dynamic.collider;
132                let other_infos = result[other_index].as_mut().unwrap();
133                let Some(info) = indexed_collider.collider.collision_info(dynamic_collider) else {
134                    continue;
135                };
136
137                other_infos.push(IndexedCollisionInfo {
138                    index: indexed_collider.index,
139                    info: -info,
140                });
141                unsafe { &mut *infos }.push(IndexedCollisionInfo {
142                    index: other_dynamic.index,
143                    info,
144                });
145            }
146        }
147
148        result
149    }
150
151    /// Computes the collisions between all colliders with the colliders of another collision manager.
152    /// Returns a list for each, which can be indexed by the specified index.
153    pub fn compute_collisions_with(
154        &self,
155        other: &Self,
156    ) -> ArrayLinkedList<Vec<IndexedCollisionInfo<C::Vector, I>>> {
157        let mut result = ArrayLinkedList::with_capacity(self.colliders.capacity());
158        for collider_index in self.colliders.indices() {
159            result.replace_front(collider_index, Vec::new());
160        }
161        for (collider_index, indexed_collider) in self.colliders.indexed() {
162            let infos = result[collider_index].as_mut().unwrap();
163            // check static collisions
164            for collider_static in &other.colliders {
165                let Some(info) = indexed_collider
166                    .collider
167                    .collision_info(&collider_static.collider)
168                else {
169                    continue;
170                };
171
172                infos.push(IndexedCollisionInfo {
173                    index: collider_static.index,
174                    info,
175                });
176            }
177        }
178        result
179    }
180}