update collision grid with position changes
authoralfadur
Wed, 24 Jul 2019 23:33:06 +0300
changeset 15282 501dfa1c8deb
parent 15281 775d7efa4e5c
child 15283 d8c4fd911b37
update collision grid with position changes
rust/hwphysics/src/collision.rs
rust/hwphysics/src/grid.rs
rust/hwphysics/src/physics.rs
--- a/rust/hwphysics/src/collision.rs	Wed Jul 24 22:49:59 2019 +0300
+++ b/rust/hwphysics/src/collision.rs	Wed Jul 24 23:33:06 2019 +0300
@@ -107,6 +107,9 @@
     }
 
     pub fn process(&mut self, land: &Land2D<u32>, updates: &crate::physics::PositionUpdates) {
+        for (id, old_position, new_position) in updates.iter() {
+            self.grid.update_position(id, old_position, new_position)
+        }
         self.grid.check_collisions(&mut self.detected_collisions);
 
         for (gear_id, collision) in self.enabled_collisions.iter() {
--- a/rust/hwphysics/src/grid.rs	Wed Jul 24 22:49:59 2019 +0300
+++ b/rust/hwphysics/src/grid.rs	Wed Jul 24 23:33:06 2019 +0300
@@ -7,16 +7,19 @@
 use integral_geometry::{GridIndex, Point, Size};
 
 struct GridBin {
-    refs: Vec<GearId>,
+    static_refs: Vec<GearId>,
     static_entries: Vec<CircleBounds>,
+
+    dynamic_refs: Vec<GearId>,
     dynamic_entries: Vec<CircleBounds>,
 }
 
 impl GridBin {
     fn new() -> Self {
         Self {
-            refs: vec![],
+            static_refs: vec![],
             static_entries: vec![],
+            dynamic_refs: vec![],
             dynamic_entries: vec![],
         }
     }
@@ -48,19 +51,65 @@
         self.index.map(fppoint_round(position))
     }
 
+    fn get_bin(&mut self, index: Point) -> &mut GridBin {
+        &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize]
+    }
+
     fn lookup_bin(&mut self, position: &FPPoint) -> &mut GridBin {
-        let index = self.bin_index(position);
-        &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize]
+        self.get_bin(self.bin_index(position))
     }
 
     pub fn insert_static(&mut self, gear_id: GearId, bounds: &CircleBounds) {
-        self.lookup_bin(&bounds.center).static_entries.push(*bounds)
+        let bin = self.lookup_bin(&bounds.center);
+        bin.static_refs.push(gear_id);
+        bin.static_entries.push(*bounds)
     }
 
     pub fn insert_dynamic(&mut self, gear_id: GearId, bounds: &CircleBounds) {
-        self.lookup_bin(&bounds.center)
-            .dynamic_entries
-            .push(*bounds)
+        let bin = self.lookup_bin(&bounds.center);
+        bin.dynamic_refs.push(gear_id);
+        bin.dynamic_entries.push(*bounds);
+    }
+
+    pub fn update_position(
+        &mut self,
+        gear_id: GearId,
+        old_position: &FPPoint,
+        new_position: &FPPoint,
+    ) {
+        let old_bin_index = self.bin_index(old_position);
+        let new_bin_index = self.bin_index(new_position);
+
+        let old_bin = self.lookup_bin(old_position);
+        if let Some(index) = old_bin.static_refs.iter().position(|id| *id == gear_id) {
+            let bounds = old_bin.static_entries.swap_remove(index);
+            old_bin.static_refs.swap_remove(index);
+
+            let new_bin = if old_bin_index == new_bin_index {
+                old_bin
+            } else {
+                self.get_bin(new_bin_index)
+            };
+
+            new_bin.dynamic_refs.push(gear_id);
+            new_bin.dynamic_entries.push(CircleBounds {
+                center: *new_position,
+                ..bounds
+            });
+        } else if let Some(index) = old_bin.dynamic_refs.iter().position(|id| *id == gear_id) {
+            if old_bin_index == new_bin_index {
+                old_bin.dynamic_entries[index].center = *new_position
+            } else {
+                let bounds = old_bin.dynamic_entries.swap_remove(index);
+                let new_bin = self.get_bin(new_bin_index);
+
+                new_bin.dynamic_refs.push(gear_id);
+                new_bin.dynamic_entries.push(CircleBounds {
+                    center: *new_position,
+                    ..bounds
+                });
+            }
+        }
     }
 
     pub fn check_collisions(&self, collisions: &mut DetectedCollisions) {
--- a/rust/hwphysics/src/physics.rs	Wed Jul 24 22:49:59 2019 +0300
+++ b/rust/hwphysics/src/physics.rs	Wed Jul 24 23:33:06 2019 +0300
@@ -93,6 +93,14 @@
         self.gear_ids.push(gear_id);
         self.shifts.push((*old_position, *new_position));
     }
+
+    pub fn iter(&self) -> impl Iterator<Item = (GearId, &FPPoint, &FPPoint)> {
+        self.gear_ids
+            .iter()
+            .cloned()
+            .zip(self.shifts.iter())
+            .map(|(id, (from, to))| (id, from, to))
+    }
 }
 
 impl PhysicsProcessor {