rhusics_ecs/collide/systems/
basic.rs1use std::fmt::Debug;
2
3use cgmath::prelude::*;
4use collision::prelude::*;
5use shrev::EventChannel;
6use specs::prelude::{Component, Entities, Entity, Join, ReadStorage, System, Write, WriteStorage};
7
8use core::{
9 basic_collide, BroadPhase, CollisionData, CollisionShape, ContactEvent, GetId, NarrowPhase,
10 NextFrame, Primitive,
11};
12
13pub struct BasicCollisionSystem<P, T, D, B, Y = ()>
36where
37 P: Primitive,
38 B: Bound,
39{
40 narrow: Option<Box<NarrowPhase<P, T, B, Y>>>,
41 broad: Option<Box<BroadPhase<D>>>,
42}
43
44impl<P, T, D, B, Y> BasicCollisionSystem<P, T, D, B, Y>
45where
46 P: Primitive + ComputeBound<B> + Send + Sync + 'static,
47 P::Point: Debug + Send + Sync + 'static,
48 <P::Point as EuclideanSpace>::Scalar: Send + Sync + 'static,
49 <P::Point as EuclideanSpace>::Diff: Debug + Send + Sync + 'static,
50 T: Component + Transform<P::Point> + Send + Sync + Clone + 'static,
51 Y: Default + Send + Sync + 'static,
52 B: Bound<Point = P::Point> + Send + Sync + 'static + Union<B, Output = B> + Clone,
53 D: HasBound<Bound = B> + From<(Entity, B)> + GetId<Entity>,
54{
55 pub fn new() -> Self {
57 Self {
58 narrow: None,
59 broad: None,
60 }
61 }
62
63 pub fn with_narrow_phase<N: NarrowPhase<P, T, B, Y> + 'static>(mut self, narrow: N) -> Self {
65 self.narrow = Some(Box::new(narrow));
66 self
67 }
68
69 pub fn with_broad_phase<V: BroadPhase<D> + 'static>(mut self, broad: V) -> Self {
71 self.broad = Some(Box::new(broad));
72 self
73 }
74}
75
76impl<'a, P, T, Y, D, B> System<'a> for BasicCollisionSystem<P, T, D, B, Y>
77where
78 P: Primitive + ComputeBound<B> + Send + Sync + 'static,
79 P::Point: Debug + Send + Sync + 'static,
80 <P::Point as EuclideanSpace>::Scalar: Send + Sync + 'static,
81 <P::Point as EuclideanSpace>::Diff: Debug + Send + Sync + 'static,
82 T: Component + Transform<P::Point> + Send + Sync + Clone + 'static,
83 Y: Default + Send + Sync + 'static,
84 B: Bound<Point = P::Point> + Send + Sync + 'static + Union<B, Output = B> + Clone,
85 D: HasBound<Bound = B> + From<(Entity, B)> + GetId<Entity>,
86{
87 type SystemData = (
88 Entities<'a>,
89 ReadStorage<'a, T>,
90 ReadStorage<'a, NextFrame<T>>,
91 WriteStorage<'a, CollisionShape<P, T, B, Y>>,
92 Write<'a, EventChannel<ContactEvent<Entity, P::Point>>>,
93 );
94
95 fn run(&mut self, system_data: Self::SystemData) {
96 let (entities, poses, next_poses, mut shapes, mut event_channel) = system_data;
97
98 if let Some(ref mut broad) = self.broad {
99 for (entity, pose, shape) in (&*entities, &poses, &mut shapes).join() {
100 shape.update(pose, next_poses.get(entity).map(|p| &p.value));
101 }
102 event_channel.iter_write(basic_collide(
103 &BasicCollisionData {
104 poses,
105 shapes,
106 next_poses,
107 entities,
108 },
109 broad,
110 &self.narrow,
111 ));
112 }
113 }
114}
115
116struct BasicCollisionData<'a, P, T, B, Y>
118where
119 P: Primitive + ComputeBound<B> + Send + Sync + 'static,
120 P::Point: Debug + Send + Sync + 'static,
121 <P::Point as EuclideanSpace>::Scalar: Send + Sync + 'static,
122 <P::Point as EuclideanSpace>::Diff: Debug + Send + Sync + 'static,
123 T: Component + Transform<P::Point> + Send + Sync + Clone + 'static,
124 Y: Default + Send + Sync + 'static,
125 B: Bound<Point = P::Point> + Send + Sync + 'static + Union<B, Output = B> + Clone,
126{
127 pub shapes: WriteStorage<'a, CollisionShape<P, T, B, Y>>,
129 pub poses: ReadStorage<'a, T>,
131 pub next_poses: ReadStorage<'a, NextFrame<T>>,
133 pub entities: Entities<'a>,
135}
136
137impl<'a, P, T, B, Y, D> CollisionData<Entity, P, T, B, Y, D> for BasicCollisionData<'a, P, T, B, Y>
138where
139 P: Primitive + ComputeBound<B> + Send + Sync + 'static,
140 P::Point: Debug + Send + Sync + 'static,
141 <P::Point as EuclideanSpace>::Scalar: Send + Sync + 'static,
142 <P::Point as EuclideanSpace>::Diff: Debug + Send + Sync + 'static,
143 T: Component + Transform<P::Point> + Send + Sync + Clone + 'static,
144 Y: Default + Send + Sync + 'static,
145 B: Bound<Point = P::Point> + Send + Sync + 'static + Union<B, Output = B> + Clone,
146 D: HasBound<Bound = B> + From<(Entity, B)> + GetId<Entity>,
147{
148 fn get_broad_data(&self) -> Vec<D> {
149 (&*self.entities, &self.shapes)
150 .join()
151 .map(|(entity, shape)| (entity, shape.bound().clone()).into())
152 .collect::<Vec<_>>()
153 }
154
155 fn get_shape(&self, id: Entity) -> Option<&CollisionShape<P, T, B, Y>> {
156 self.shapes.get(id)
157 }
158
159 fn get_pose(&self, id: Entity) -> Option<&T> {
160 self.poses.get(id)
161 }
162
163 fn get_next_pose(&self, id: Entity) -> Option<&T> {
164 self.next_poses.get(id).as_ref().map(|p| &p.value)
165 }
166}