Browse Source

Clunkily use a collision world instead of manual broad phase

Getty Ritter 4 years ago
parent
commit
86edfda8c0
5 changed files with 65 additions and 72 deletions
  1. 21 11
      src/com.rs
  2. 1 9
      src/main.rs
  3. 14 10
      src/res.rs
  4. 28 42
      src/sys/physics.rs
  5. 1 0
      src/types.rs

+ 21 - 11
src/com.rs

@@ -1,5 +1,6 @@
 use specs::world::WorldExt;
 use specs::{Component, NullStorage, VecStorage};
+use crate::types::World;
 
 /// Register all the components with the world.
 pub fn register(world: &mut specs::World) {
@@ -112,21 +113,30 @@ pub struct Collision {
 #[derive(Component)]
 #[storage(VecStorage)]
 pub struct Blocking {
-    pub volume: Box<dyn ncollide2d::shape::Shape<f32>>,
+    pub handle: ncollide2d::pipeline::CollisionObjectSlabHandle,
 }
 
 impl Blocking {
-    pub fn new() -> Blocking {
-        Default::default()
-    }
-}
-
-impl Default for Blocking {
-    fn default() -> Blocking {
+    pub fn new_shape<S: ncollide2d::shape::Shape<f32>>(w: &mut World, volume: S) -> Blocking {
+        let (handle, _) = w.add(
+            nalgebra::geometry::Isometry::identity(),
+            ncollide2d::shape::ShapeHandle::new(volume),
+            ncollide2d::pipeline::CollisionGroups::new(),
+            ncollide2d::pipeline::object::GeometricQueryType::Proximity(0.0),
+            None,
+        );
         Blocking {
-            volume: Box::new(ncollide2d::shape::Cuboid::new(nalgebra::Vector2::new(
-                11.0, 11.0,
-            ))),
+            handle,
         }
     }
+
+    pub fn new_box(w: &mut World) -> Blocking {
+        Blocking::new_shape(w, ncollide2d::shape::Cuboid::new(nalgebra::Vector2::new(
+            11.0, 11.0,
+        )))
+    }
+
+    pub fn new_ball(w: &mut World) -> Blocking {
+        Blocking::new_shape(w, ncollide2d::shape::Ball::new(8.0))
+    }
 }

+ 1 - 9
src/main.rs

@@ -60,6 +60,7 @@ fn main() -> Result<(), ggez::error::GameError> {
     let mut world = specs::World::new();
     com::register(&mut world);
 
+    world.insert(ncollide2d::world::CollisionWorld::<f32, Option<specs::Entity>>::new(0.1));
     res::world_from_file(&mut world, "assets/main.tmx");
 
     // Make a Context and an EventLoop.
@@ -83,15 +84,6 @@ fn main() -> Result<(), ggez::error::GameError> {
     world.insert(sprites);
     world.insert(res::KeySet::new());
 
-    let broad_phase: types::BPhase = nc::DBVTBroadPhase::new(0.0f32);
-    world.insert(broad_phase);
-
-    let narrow_phase: types::NPhase = nc::NarrowPhase::new(
-        Box::new(nc::DefaultContactDispatcher::new()),
-        Box::new(nc::DefaultProximityDispatcher::new()),
-    );
-    world.insert(narrow_phase);
-
     let mut my_game = MyGame { world };
 
     event::run(&mut ctx, &mut evloop, &mut my_game)

+ 14 - 10
src/res.rs

@@ -1,5 +1,6 @@
 use crate::com::*;
 use crate::consts;
+use crate::types::World;
 
 use specs::world::{Builder, WorldExt};
 use std::path::Path;
@@ -55,6 +56,13 @@ pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) {
                     let y = y as f32 * consts::TILE_SIZE;
                     let u = ((n - 1) % 32) as u8;
                     let v = ((n - u as u32 - 1) / 32) as u8;
+                    let blocking = if tilesets[0].tiles[(n-1) as usize].properties["pass"]
+                        == tiled::PropertyValue::BoolValue(false) {
+                            let mut h = w.write_resource::<World>();
+                            Some(Blocking::new_box(&mut h))
+                        } else {
+                            None
+                        };
                     let mut e = w
                         .create_entity()
                         .with(Position { x, y })
@@ -65,13 +73,7 @@ pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) {
                         DrawLayer::Decoration => e.with(Decoration),
                     };
 
-                    let e = if tilesets[0].tiles[(n-1) as usize].properties["pass"]
-                        == tiled::PropertyValue::BoolValue(false)
-                    {
-                        e.with(Blocking::new())
-                    } else {
-                        e
-                    };
+                    let e = if let Some(b) = blocking { e.with(b) } else { e };
                     e.build();
                 }
             }
@@ -79,6 +81,10 @@ pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) {
     }
 
     // create the player
+    let ball = {
+        let mut h = w.write_resource::<World>();
+        Blocking::new_ball(&mut h)
+    };
     w.create_entity()
         .with(Position {
             x: 3.0 * consts::TILE_SIZE,
@@ -91,8 +97,6 @@ pub fn world_from_file<P: AsRef<Path>>(w: &mut specs::World, path: P) {
         .with(Collision {
             has_collision: false,
         })
-        .with(Blocking {
-            volume: Box::new(ncollide2d::shape::Ball::new(10.0)),
-        })
+        .with(ball)
         .build();
 }

+ 28 - 42
src/sys/physics.rs

@@ -1,31 +1,10 @@
 use crate::com::{Blocking, Collision, Position, Velocity};
 use crate::game::MyGame;
-use crate::types::{BPhase, NPhase};
+use crate::types::World;
 
 use nalgebra::{Isometry2, Vector2};
-use ncollide2d::broad_phase::{
-    broad_phase::BroadPhase, broad_phase::BroadPhaseProxyHandle, BroadPhaseInterferenceHandler,
-};
 use specs::{Join, RunNow};
 
-struct InterferenceHandler<'a> {
-    collisions: specs::WriteStorage<'a, Collision>,
-}
-
-impl<'a> BroadPhaseInterferenceHandler<specs::Entity> for InterferenceHandler<'a> {
-    fn is_interference_allowed(&mut self, a: &specs::Entity, b: &specs::Entity) -> bool {
-        // Prevent self-collision.
-        *a != *b
-    }
-
-    fn interference_started(&mut self, a: &specs::Entity, b: &specs::Entity) {
-        self.collisions.get_mut(*a).map(|r| r.has_collision = true);
-        self.collisions.get_mut(*b).map(|r| r.has_collision = true);
-    }
-
-    fn interference_stopped(&mut self, _: &specs::Entity, _: &specs::Entity) {}
-}
-
 struct Collide;
 
 impl<'a> specs::System<'a> for Collide {
@@ -35,19 +14,14 @@ impl<'a> specs::System<'a> for Collide {
         specs::ReadStorage<'a, Velocity>,
         specs::ReadStorage<'a, Blocking>,
         specs::WriteStorage<'a, Collision>,
-        specs::WriteExpect<'a, BPhase>,
-        specs::WriteExpect<'a, NPhase>,
+        specs::WriteExpect<'a, World>,
     );
 
     fn run(
         &mut self,
-        (entities, position, velocity, blocking, mut collisions, mut bf, _narrow): Self::SystemData,
+        (entities, position, velocity, blocking, mut collisions, mut w): Self::SystemData,
     ) {
-        let _: Vec<()> = (&mut collisions)
-            .join()
-            .map(|c| c.has_collision = false)
-            .collect();
-        let handles: Vec<BroadPhaseProxyHandle> = (&entities, &position, &blocking)
+        let _: Vec<()> = (&entities, &position, &blocking)
             .join()
             .map(|(e, pos, bl)| {
                 let np = if let Some(vel) = velocity.get(e) {
@@ -55,19 +29,31 @@ impl<'a> specs::System<'a> for Collide {
                 } else {
                     pos.clone()
                 };
-                bf.create_proxy(
-                    bl.volume
-                        .aabb(&Isometry2::new(Vector2::new(np.x, np.y), nalgebra::zero())),
-                    e,
-                )
+                let obj = w.get_mut(bl.handle).unwrap();
+                *obj.data_mut() = Some(e);
+                obj.set_position(
+                    Isometry2::new(Vector2::new(np.x, np.y), nalgebra::zero()));
             })
             .collect();
-
-        bf.update(&mut InterferenceHandler {
-            collisions: collisions,
-        });
-
-        bf.remove(&handles, &mut |_, _| {});
+        w.update();
+        for ev in w.proximity_events() {
+            if ev.new_status == ncollide2d::query::Proximity::Intersecting {
+                if let Some(e) = w.collision_object(ev.collider1).unwrap().data() {
+                    collisions.get_mut(*e).map(|r| r.has_collision = true);
+                }
+                if let Some(e) = w.collision_object(ev.collider2).unwrap().data() {
+                    collisions.get_mut(*e).map(|r| r.has_collision = true);
+                }
+            } else {
+                if let Some(e) = w.collision_object(ev.collider1).unwrap().data() {
+                    collisions.get_mut(*e).map(|r| r.has_collision = false);
+                }
+                if let Some(e) = w.collision_object(ev.collider2).unwrap().data() {
+                    collisions.get_mut(*e).map(|r| r.has_collision = false);
+                }
+            }
+        }
+        w.clear_events();
     }
 }
 
@@ -131,5 +117,5 @@ pub fn systems(game: &mut MyGame) {
     Collide.run_now(&game.world);
     // Intersection.run_now(&game.world.res);
     Physics.run_now(&game.world);
-    ResetCollision.run_now(&game.world);
+    // ResetCollision.run_now(&game.world);
 }

+ 1 - 0
src/types.rs

@@ -4,3 +4,4 @@ pub type BPhase = ncollide2d::broad_phase::DBVTBroadPhase<
     specs::Entity,
 >;
 pub type NPhase = ncollide2d::narrow_phase::NarrowPhase<f32, ()>;
+pub type World = ncollide2d::world::CollisionWorld<f32, Option<specs::Entity>>;