Clunkily use a collision world instead of manual broad phase
Getty Ritter
6 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 | } |