diff --git a/panda/src/collide/collisionTraverser.cxx b/panda/src/collide/collisionTraverser.cxx index 4eab14d3b4..14d368c917 100644 --- a/panda/src/collide/collisionTraverser.cxx +++ b/panda/src/collide/collisionTraverser.cxx @@ -265,7 +265,7 @@ traverse(const NodePath &root) { #endif // DO_COLLISION_RECORDING CollisionLevelState level_state(root); - prepare_colliders(level_state); + prepare_colliders(level_state, root); Handlers::iterator hi; for (hi = _handlers.begin(); hi != _handlers.end(); ++hi) { @@ -399,29 +399,38 @@ write(ostream &out, int indent_level) const { // Description: //////////////////////////////////////////////////////////////////// void CollisionTraverser:: -prepare_colliders(CollisionLevelState &level_state) { +prepare_colliders(CollisionLevelState &level_state, const NodePath &root) { level_state.clear(); level_state.reserve(_colliders.size()); int i = 0; while (i < (int)_ordered_colliders.size()) { NodePath cnode_path = _ordered_colliders[i]; - if (!cnode_path.is_empty() && - cnode_path.node()->is_of_type(CollisionNode::get_class_type())) { - CollisionNode *cnode = DCAST(CollisionNode, cnode_path.node()); - - CollisionLevelState::ColliderDef def; - def._node = cnode; - def._node_path = cnode_path; - - int num_solids = cnode->get_num_solids(); - for (int s = 0; s < num_solids; s++) { - CollisionSolid *collider = cnode->get_solid(s); - def._collider = collider; - level_state.prepare_collider(def); +#ifndef NDEBUG + if (!cnode_path.is_same_graph(root)) { + collide_cat.error() + << "Collider " << cnode_path + << " is not in scene graph. Dropping from traverser.\n"; + // This is safe to do while traversing the list of colliders, + // because we do not increment i in this case. + remove_collider(cnode_path); + } else +#endif + { + CollisionNode *cnode = DCAST(CollisionNode, cnode_path.node()); + + CollisionLevelState::ColliderDef def; + def._node = cnode; + def._node_path = cnode_path; + + int num_solids = cnode->get_num_solids(); + for (int s = 0; s < num_solids; s++) { + CollisionSolid *collider = cnode->get_solid(s); + def._collider = collider; + level_state.prepare_collider(def); + } + i++; } - i++; - } } } diff --git a/panda/src/collide/collisionTraverser.h b/panda/src/collide/collisionTraverser.h index 82f6ed4aae..d00faef89d 100644 --- a/panda/src/collide/collisionTraverser.h +++ b/panda/src/collide/collisionTraverser.h @@ -83,7 +83,7 @@ PUBLISHED: void write(ostream &out, int indent_level) const; private: - void prepare_colliders(CollisionLevelState &state); + void prepare_colliders(CollisionLevelState &state, const NodePath &root); void r_traverse(CollisionLevelState &level_state); diff --git a/panda/src/pgraph/nodePath.I b/panda/src/pgraph/nodePath.I index 2dd792894b..0e27baf36b 100644 --- a/panda/src/pgraph/nodePath.I +++ b/panda/src/pgraph/nodePath.I @@ -262,13 +262,6 @@ node() const { // given key will never be reused for a different // instance (unless the app has been running long enough // that we overflow the integer key value). -// -// There are a few special case circumstances that can -// cause the key for a particular instance to be -// changed. These all involve different instances being -// collapsed into the same instance by some scene graph -// operation (for instance, detaching a node below an -// instanced node). //////////////////////////////////////////////////////////////////// INLINE int NodePath:: get_key() const { @@ -278,6 +271,27 @@ get_key() const { return _head->get_key(); } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::is_same_graph +// Access: Published +// Description: Returns true if the node represented by this NodePath +// is parented within the same graph as that of the +// other NodePath. This is essentially the same thing +// as asking whether the top node of both NodePaths is +// the same (e.g., both "render"). +//////////////////////////////////////////////////////////////////// +INLINE bool NodePath:: +is_same_graph(const NodePath &other) const { + // Actually, it's possible for the top nodes to be the same, but the + // NodePaths still to be considered in different graphs. This will + // happen if one of the top nodes is considered a different + // instance--for instance, render.instance_to(NodePath()) returns a + // different instance of render that appears to have the same top + // node. But this is a very rare thing to do. + int a_count, b_count; + return (find_common_ancestor(*this, other, a_count, b_count) != (NodePathComponent *)NULL); +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::get_num_children // Access: Published diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 1e52e83939..5b2f2ac8e5 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -179,6 +179,8 @@ PUBLISHED: INLINE int get_key() const; + INLINE bool is_same_graph(const NodePath &other) const; + // Methods that return collections of NodePaths derived from or // related to this one.