Browse Source

remove colliders when you remove the handler

David Rose 22 years ago
parent
commit
90fb2ebf89
2 changed files with 60 additions and 12 deletions
  1. 58 12
      panda/src/collide/collisionTraverser.cxx
  2. 2 0
      panda/src/collide/collisionTraverser.h

+ 58 - 12
panda/src/collide/collisionTraverser.cxx

@@ -142,14 +142,11 @@ remove_collider(CollisionNode *node) {
 
 
   // Update the set of handlers.
   // Update the set of handlers.
   Handlers::iterator hi = _handlers.find(handler);
   Handlers::iterator hi = _handlers.find(handler);
-  // It's possible that the handler doesn't exist in the list (it may
-  // have removed itself if it detected some internal error).
-  if (hi != _handlers.end()) {
-    (*hi).second--;
-    nassertr((*hi).second >= 0, false);
-    if ((*hi).second == 0) {
-      _handlers.erase(hi);
-    }
+  nassertr(hi != _handlers.end(), false);
+  (*hi).second--;
+  nassertr((*hi).second >= 0, false);
+  if ((*hi).second == 0) {
+    _handlers.erase(hi);
   }
   }
 
 
   _colliders.erase(ci);
   _colliders.erase(ci);
@@ -259,10 +256,7 @@ traverse(const NodePath &root) {
   while (hi != _handlers.end()) {
   while (hi != _handlers.end()) {
     if (!(*hi).first->end_group()) {
     if (!(*hi).first->end_group()) {
       // This handler wants to remove itself from the traversal list.
       // This handler wants to remove itself from the traversal list.
-      Handlers::iterator hnext = hi;
-      ++hnext;
-      _handlers.erase(hi);
-      hi = hnext;
+      hi = remove_handler(hi);
     } else {
     } else {
       ++hi;
       ++hi;
     }
     }
@@ -678,3 +672,55 @@ compare_collider_to_geom(CollisionEntry &entry, Geom *geom,
     }
     }
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionTraverser::remove_handler
+//       Access: Private
+//  Description: Removes the indicated CollisionHandler from the list
+//               of handlers to be processed, and returns the iterator
+//               to the next handler in the list.  This is designed to
+//               be called safely from within a traversal of the handler
+//               list.
+//
+//               This also removes any colliders that depend on this
+//               handler, to keep internal structures intact.
+////////////////////////////////////////////////////////////////////
+CollisionTraverser::Handlers::iterator CollisionTraverser::
+remove_handler(CollisionTraverser::Handlers::iterator hi) {
+  nassertr(hi != _handlers.end(), hi);
+
+  CollisionHandler *handler = (*hi).first;
+  Handlers::iterator hnext = hi;
+  ++hnext;
+  _handlers.erase(hi);
+  hi = hnext;
+
+  // Now scan for colliders that reference this handler.
+  Colliders::iterator ci;
+  ci = _colliders.begin();
+  while (ci != _colliders.end()) {
+    if ((*ci).second == handler) {
+      // This collider references this handler; remove it.
+      PT(CollisionNode) node = (*ci).first;
+
+      Colliders::iterator cnext = ci;
+      ++cnext;
+      _colliders.erase(ci);
+      ci = cnext;
+
+      // Also remove it from the ordered list.
+      OrderedColliders::iterator oci =
+        find(_ordered_colliders.begin(), _ordered_colliders.end(), node);
+      nassertr(oci != _ordered_colliders.end(), hi);
+      _ordered_colliders.erase(oci);
+      
+      nassertr(_ordered_colliders.size() == _colliders.size(), false);
+
+    } else {
+      // This collider references some other handler; keep it.
+      ++ci;
+    }
+  }
+
+  return hi;
+}

+ 2 - 0
panda/src/collide/collisionTraverser.h

@@ -105,6 +105,8 @@ private:
   typedef pmap<PT(CollisionHandler), int> Handlers;
   typedef pmap<PT(CollisionHandler), int> Handlers;
   Handlers _handlers;
   Handlers _handlers;
 
 
+  Handlers::iterator remove_handler(Handlers::iterator hi);
+
 #ifdef DO_COLLISION_RECORDING
 #ifdef DO_COLLISION_RECORDING
   CollisionRecorder *_recorder;
   CollisionRecorder *_recorder;
 #endif  // DO_COLLISION_RECORDING
 #endif  // DO_COLLISION_RECORDING