Clunkily use a collision world instead of manual broad phase
Getty Ritter
5 years ago
1 | 1 | use specs::world::WorldExt; |
2 | 2 | use specs::{Component, NullStorage, VecStorage}; |
3 | use crate::types::World; | |
3 | 4 | |
4 | 5 | /// Register all the components with the world. |
5 | 6 | pub fn register(world: &mut specs::World) { |
112 | 113 | #[derive(Component)] |
113 | 114 | #[storage(VecStorage)] |
114 | 115 | pub struct Blocking { |
115 |
pub |
|
116 | pub handle: ncollide2d::pipeline::CollisionObjectSlabHandle, | |
116 | 117 | } |
117 | 118 | |
118 | 119 | impl Blocking { |
119 | pub fn new() -> Blocking { | |
120 | Default::default() | |
120 | pub fn new_shape<S: ncollide2d::shape::Shape<f32>>(w: &mut World, volume: S) -> Blocking { | |
121 | let (handle, _) = w.add( | |
122 | nalgebra::geometry::Isometry::identity(), | |
123 | ncollide2d::shape::ShapeHandle::new(volume), | |
124 | ncollide2d::pipeline::CollisionGroups::new(), | |
125 | ncollide2d::pipeline::object::GeometricQueryType::Proximity(0.0), | |
126 | None, | |
127 | ); | |
128 | Blocking { | |
129 | handle, | |
130 | } | |
131 | } | |
132 | ||
133 | pub fn new_box(w: &mut World) -> Blocking { | |
134 | Blocking::new_shape(w, ncollide2d::shape::Cuboid::new(nalgebra::Vector2::new( | |
135 | 11.0, 11.0, | |
136 | ))) | |
137 | } | |
138 | ||
139 | pub fn new_ball(w: &mut World) -> Blocking { | |
140 | Blocking::new_shape(w, ncollide2d::shape::Ball::new(8.0)) | |
121 | 141 | } |
122 | 142 | } |
123 | ||
124 | impl Default for Blocking { | |
125 | fn default() -> Blocking { | |
126 | Blocking { | |
127 | volume: Box::new(ncollide2d::shape::Cuboid::new(nalgebra::Vector2::new( | |
128 | 11.0, 11.0, | |
129 | ))), | |
130 | } | |
131 | } | |
132 | } |
60 | 60 | let mut world = specs::World::new(); |
61 | 61 | com::register(&mut world); |
62 | 62 | |
63 | world.insert(ncollide2d::world::CollisionWorld::<f32, Option<specs::Entity>>::new(0.1)); | |
63 | 64 | res::world_from_file(&mut world, "assets/main.tmx"); |
64 | 65 | |
65 | 66 | // Make a Context and an EventLoop. |
83 | 84 | world.insert(sprites); |
84 | 85 | world.insert(res::KeySet::new()); |
85 | 86 | |
86 | let broad_phase: types::BPhase = nc::DBVTBroadPhase::new(0.0f32); | |
87 | world.insert(broad_phase); | |
88 | ||
89 | let narrow_phase: types::NPhase = nc::NarrowPhase::new( | |
90 | Box::new(nc::DefaultContactDispatcher::new()), | |
91 | Box::new(nc::DefaultProximityDispatcher::new()), | |
92 | ); | |
93 | world.insert(narrow_phase); | |
94 | ||
95 | 87 | let mut my_game = MyGame { world }; |
96 | 88 | |
97 | 89 | event::run(&mut ctx, &mut evloop, &mut my_game) |
1 | 1 | use crate::com::*; |
2 | 2 | use crate::consts; |
3 | use crate::types::World; | |
3 | 4 | |
4 | 5 | use specs::world::{Builder, WorldExt}; |
5 | 6 | use std::path::Path; |
55 | 56 | let y = y as f32 * consts::TILE_SIZE; |
56 | 57 | let u = ((n - 1) % 32) as u8; |
57 | 58 | let v = ((n - u as u32 - 1) / 32) as u8; |
59 | let blocking = if tilesets[0].tiles[(n-1) as usize].properties["pass"] | |
60 | == tiled::PropertyValue::BoolValue(false) { | |
61 | let mut h = w.write_resource::<World>(); | |
62 | Some(Blocking::new_box(&mut h)) | |
63 | } else { | |
64 | None | |
65 | }; | |
58 | 66 | let mut e = w |
59 | 67 | .create_entity() |
60 | 68 | .with(Position { x, y }) |
65 | 73 | DrawLayer::Decoration => e.with(Decoration), |
66 | 74 | }; |
67 | 75 | |
68 | let e = if tilesets[0].tiles[(n-1) as usize].properties["pass"] | |
69 | == tiled::PropertyValue::BoolValue(false) | |
70 | { | |
71 | e.with(Blocking::new()) | |
72 | } else { | |
73 | e | |
74 |
|
|
76 | let e = if let Some(b) = blocking { e.with(b) } else { e }; | |
75 | 77 | e.build(); |
76 | 78 | } |
77 | 79 | } |
79 | 81 | } |
80 | 82 | |
81 | 83 | // create the player |
84 | let ball = { | |
85 | let mut h = w.write_resource::<World>(); | |
86 | Blocking::new_ball(&mut h) | |
87 | }; | |
82 | 88 | w.create_entity() |
83 | 89 | .with(Position { |
84 | 90 | x: 3.0 * consts::TILE_SIZE, |
91 | 97 | .with(Collision { |
92 | 98 | has_collision: false, |
93 | 99 | }) |
94 | .with(Blocking { | |
95 | volume: Box::new(ncollide2d::shape::Ball::new(10.0)), | |
96 |
|
|
100 | .with(ball) | |
97 | 101 | .build(); |
98 | 102 | } |
1 | 1 | use crate::com::{Blocking, Collision, Position, Velocity}; |
2 | 2 | use crate::game::MyGame; |
3 |
use crate::types:: |
|
3 | use crate::types::World; | |
4 | 4 | |
5 | 5 | use nalgebra::{Isometry2, Vector2}; |
6 | use ncollide2d::broad_phase::{ | |
7 | broad_phase::BroadPhase, broad_phase::BroadPhaseProxyHandle, BroadPhaseInterferenceHandler, | |
8 | }; | |
9 | 6 | use specs::{Join, RunNow}; |
10 | ||
11 | struct InterferenceHandler<'a> { | |
12 | collisions: specs::WriteStorage<'a, Collision>, | |
13 | } | |
14 | ||
15 | impl<'a> BroadPhaseInterferenceHandler<specs::Entity> for InterferenceHandler<'a> { | |
16 | fn is_interference_allowed(&mut self, a: &specs::Entity, b: &specs::Entity) -> bool { | |
17 | // Prevent self-collision. | |
18 | *a != *b | |
19 | } | |
20 | ||
21 | fn interference_started(&mut self, a: &specs::Entity, b: &specs::Entity) { | |
22 | self.collisions.get_mut(*a).map(|r| r.has_collision = true); | |
23 | self.collisions.get_mut(*b).map(|r| r.has_collision = true); | |
24 | } | |
25 | ||
26 | fn interference_stopped(&mut self, _: &specs::Entity, _: &specs::Entity) {} | |
27 | } | |
28 | 7 | |
29 | 8 | struct Collide; |
30 | 9 | |
35 | 14 | specs::ReadStorage<'a, Velocity>, |
36 | 15 | specs::ReadStorage<'a, Blocking>, |
37 | 16 | specs::WriteStorage<'a, Collision>, |
38 | specs::WriteExpect<'a, BPhase>, | |
39 | specs::WriteExpect<'a, NPhase>, | |
17 | specs::WriteExpect<'a, World>, | |
40 | 18 | ); |
41 | 19 | |
42 | 20 | fn run( |
43 | 21 | &mut self, |
44 |
(entities, position, velocity, blocking, mut collisions, mut |
|
22 | (entities, position, velocity, blocking, mut collisions, mut w): Self::SystemData, | |
45 | 23 | ) { |
46 | let _: Vec<()> = (&mut collisions) | |
47 | .join() | |
48 | .map(|c| c.has_collision = false) | |
49 | .collect(); | |
50 |
let |
|
24 | let _: Vec<()> = (&entities, &position, &blocking) | |
51 | 25 | .join() |
52 | 26 | .map(|(e, pos, bl)| { |
53 | 27 | let np = if let Some(vel) = velocity.get(e) { |
55 | 29 | } else { |
56 | 30 | pos.clone() |
57 | 31 | }; |
58 | bf.create_proxy( | |
59 | bl.volume | |
60 | .aabb(&Isometry2::new(Vector2::new(np.x, np.y), nalgebra::zero())), | |
61 | e, | |
62 |
|
|
32 | let obj = w.get_mut(bl.handle).unwrap(); | |
33 | *obj.data_mut() = Some(e); | |
34 | obj.set_position( | |
35 | Isometry2::new(Vector2::new(np.x, np.y), nalgebra::zero())); | |
63 | 36 | }) |
64 | 37 | .collect(); |
65 | ||
66 | bf.update(&mut InterferenceHandler { | |
67 | collisions: collisions, | |
68 | }); | |
69 | ||
70 | bf.remove(&handles, &mut |_, _| {}); | |
38 | w.update(); | |
39 | for ev in w.proximity_events() { | |
40 | if ev.new_status == ncollide2d::query::Proximity::Intersecting { | |
41 | if let Some(e) = w.collision_object(ev.collider1).unwrap().data() { | |
42 | collisions.get_mut(*e).map(|r| r.has_collision = true); | |
43 | } | |
44 | if let Some(e) = w.collision_object(ev.collider2).unwrap().data() { | |
45 | collisions.get_mut(*e).map(|r| r.has_collision = true); | |
46 | } | |
47 | } else { | |
48 | if let Some(e) = w.collision_object(ev.collider1).unwrap().data() { | |
49 | collisions.get_mut(*e).map(|r| r.has_collision = false); | |
50 | } | |
51 | if let Some(e) = w.collision_object(ev.collider2).unwrap().data() { | |
52 | collisions.get_mut(*e).map(|r| r.has_collision = false); | |
53 | } | |
54 | } | |
55 | } | |
56 | w.clear_events(); | |
71 | 57 | } |
72 | 58 | } |
73 | 59 | |
131 | 117 | Collide.run_now(&game.world); |
132 | 118 | // Intersection.run_now(&game.world.res); |
133 | 119 | Physics.run_now(&game.world); |
134 |
|
|
120 | // ResetCollision.run_now(&game.world); | |
135 | 121 | } |