class World(object): """ The World models basically everything about a map, including gravity, ambient light, the sky, and all map objects. """ def __init__(self, camera, debug=False, audio3d=None, client=None, server=None): self.objects = {} self.incarnators = [] self.collidables = set() self.updatables = set() self.updatables_to_add = set() self.garbage = set() self.scene = NodePath('world') # Set up the physics world. TODO: let maps set gravity. self.gravity = DEFAULT_GRAVITY self.physics = BulletWorld() self.physics.set_gravity(self.gravity) self.debug = debug if debug: debug_node = BulletDebugNode('Debug') debug_node.show_wireframe(True) debug_node.show_constraints(True) debug_node.show_bounding_boxes(False) debug_node.show_normals(False) np = self.scene.attach_new_node(debug_node) np.show() self.physics.set_debug_node(debug_node) def get_incarn(self): return random.choice(self.incarnators) def attach(self, obj): assert hasattr(obj, 'world') and hasattr(obj, 'name') assert obj.name not in self.objects obj.world = self if obj.name.startswith('Incarnator'): self.incarnators.append(obj) if hasattr(obj, 'create_node') and hasattr(obj, 'create_solid'): # Let each object define it's own NodePath, then reparent them. obj.node = obj.create_node() obj.solid = obj.create_solid() if obj.solid: if isinstance(obj.solid, BulletRigidBodyNode): self.physics.attach_rigid_body(obj.solid) elif isinstance(obj.solid, BulletGhostNode): self.physics.attach_ghost(obj.solid) if obj.node: if obj.solid: # If this is a solid visible object, create a new physics node and reparent the visual node to that. phys_node = self.scene.attach_new_node(obj.solid) obj.node.reparent_to(phys_node) obj.node = phys_node else: # Otherwise just reparent the visual node to the root. obj.node.reparent_to(self.scene) elif obj.solid: obj.node = self.scene.attach_new_node(obj.solid) if obj.solid and obj.collide_bits is not None: obj.solid.set_into_collide_mask(obj.collide_bits) self.objects[obj.name] = obj # Let the object know it has been attached. obj.attached() return obj def create_hector(self, name=None): # TODO: get random incarn, start there h = self.attach(Hector(name)) h.move((0, 15, 0)) return h def register_updater(self, obj): assert isinstance(obj, WorldObject) self.updatables.add(obj) def register_updater_later(self, obj): assert isinstance(obj, WorldObject) self.updatables_to_add.add(obj) def update(self, task): """ Called every frame to update the physics, etc. """ dt = globalClock.getDt() for obj in self.updatables_to_add: self.updatables.add(obj) self.updatables_to_add = set() for obj in self.updatables: obj.update(dt) self.updatables -= self.garbage self.collidables -= self.garbage while True: if len(self.garbage) < 1: break trash = self.garbage.pop() if (isinstance(trash.solid, BulletGhostNode)): self.physics.remove_ghost(trash.solid) if (isinstance(trash.solid, BulletRigidBodyNode)): self.physics.remove_rigid_body(trash.solid) if hasattr(trash, 'dead'): trash.dead() trash.node.remove_node() del (trash) self.physics.do_physics(dt) for obj in self.collidables: result = self.physics.contact_test(obj.node.node()) for contact in result.get_contacts(): obj1 = self.objects.get(contact.get_node0().get_name()) obj2 = self.objects.get(contact.get_node1().get_name()) if obj1 and obj2: # Check the collision bits to see if the two objects should collide. should_collide = obj1.collide_bits & obj2.collide_bits if not should_collide.is_zero(): pt = contact.get_manifold_point() if obj1 in self.collidables: obj1.collision(obj2, pt, True) if obj2 in self.collidables: obj2.collision(obj1, pt, False) return task.cont
class World (object): """ The World models basically everything about a map, including gravity, ambient light, the sky, and all map objects. """ def __init__(self, camera, debug=False, audio3d=None, client=None, server=None): self.objects = {} self.incarnators = [] self.collidables = set() self.updatables = set() self.updatables_to_add = set() self.garbage = set() self.scene = NodePath('world') # Set up the physics world. TODO: let maps set gravity. self.gravity = DEFAULT_GRAVITY self.physics = BulletWorld() self.physics.set_gravity(self.gravity) self.debug = debug if debug: debug_node = BulletDebugNode('Debug') debug_node.show_wireframe(True) debug_node.show_constraints(True) debug_node.show_bounding_boxes(False) debug_node.show_normals(False) np = self.scene.attach_new_node(debug_node) np.show() self.physics.set_debug_node(debug_node) def get_incarn(self): return random.choice(self.incarnators) def attach(self, obj): assert hasattr(obj, 'world') and hasattr(obj, 'name') assert obj.name not in self.objects obj.world = self if obj.name.startswith('Incarnator'): self.incarnators.append(obj) if hasattr(obj, 'create_node') and hasattr(obj, 'create_solid'): # Let each object define it's own NodePath, then reparent them. obj.node = obj.create_node() obj.solid = obj.create_solid() if obj.solid: if isinstance(obj.solid, BulletRigidBodyNode): self.physics.attach_rigid_body(obj.solid) elif isinstance(obj.solid, BulletGhostNode): self.physics.attach_ghost(obj.solid) if obj.node: if obj.solid: # If this is a solid visible object, create a new physics node and reparent the visual node to that. phys_node = self.scene.attach_new_node(obj.solid) obj.node.reparent_to(phys_node) obj.node = phys_node else: # Otherwise just reparent the visual node to the root. obj.node.reparent_to(self.scene) elif obj.solid: obj.node = self.scene.attach_new_node(obj.solid) if obj.solid and obj.collide_bits is not None: obj.solid.set_into_collide_mask(obj.collide_bits) self.objects[obj.name] = obj # Let the object know it has been attached. obj.attached() return obj def create_hector(self, name=None): # TODO: get random incarn, start there h = self.attach(Hector(name)) h.move((0, 15, 0)) return h def register_updater(self, obj): assert isinstance(obj, WorldObject) self.updatables.add(obj) def register_updater_later(self, obj): assert isinstance(obj, WorldObject) self.updatables_to_add.add(obj) def update(self, task): """ Called every frame to update the physics, etc. """ dt = globalClock.getDt() for obj in self.updatables_to_add: self.updatables.add(obj) self.updatables_to_add = set() for obj in self.updatables: obj.update(dt) self.updatables -= self.garbage self.collidables -= self.garbage while True: if len(self.garbage) < 1: break; trash = self.garbage.pop() if(isinstance(trash.solid, BulletGhostNode)): self.physics.remove_ghost(trash.solid) if(isinstance(trash.solid, BulletRigidBodyNode)): self.physics.remove_rigid_body(trash.solid) if hasattr(trash, 'dead'): trash.dead() trash.node.remove_node() del(trash) self.physics.do_physics(dt) for obj in self.collidables: result = self.physics.contact_test(obj.node.node()) for contact in result.get_contacts(): obj1 = self.objects.get(contact.get_node0().get_name()) obj2 = self.objects.get(contact.get_node1().get_name()) if obj1 and obj2: # Check the collision bits to see if the two objects should collide. should_collide = obj1.collide_bits & obj2.collide_bits if not should_collide.is_zero(): pt = contact.get_manifold_point() if obj1 in self.collidables: obj1.collision(obj2, pt, True) if obj2 in self.collidables: obj2.collision(obj1, pt, False) return task.cont
class World (object): """ The World models basically everything about a map, including gravity, ambient light, the sky, and all map objects. """ def __init__(self, camera, debug=False, audio3d=None, client=None, server=None): self.objects = {} self.incarnators = [] self.collidables = set() self.updatables = set() self.updatables_to_add = set() self.garbage = set() self.render = NodePath('world') self.camera = camera self.audio3d = audio3d self.ambient = self._make_ambient() self.celestials = CompositeObject() self.sky = self.attach(Sky()) # Set up the physics world. TODO: let maps set gravity. self.gravity = DEFAULT_GRAVITY self.physics = BulletWorld() self.physics.set_gravity(self.gravity) self.debug = debug self.client = client self.server = server if debug: debug_node = BulletDebugNode('Debug') debug_node.show_wireframe(True) debug_node.show_constraints(True) debug_node.show_bounding_boxes(False) debug_node.show_normals(False) np = self.render.attach_new_node(debug_node) np.show() self.physics.set_debug_node(debug_node) def _make_ambient(self): alight = AmbientLight('ambient') alight.set_color(VBase4(*DEFAULT_AMBIENT_COLOR)) node = self.render.attach_new_node(alight) self.render.set_light(node) return node def attach(self, obj): assert hasattr(obj, 'world') and hasattr(obj, 'name') assert obj.name not in self.objects obj.world = self if obj.name.startswith('Incarnator'): self.incarnators.append(obj) if hasattr(obj, 'create_node') and hasattr(obj, 'create_solid'): # Let each object define it's own NodePath, then reparent them. obj.node = obj.create_node() obj.solid = obj.create_solid() if obj.solid: if isinstance(obj.solid, BulletRigidBodyNode): self.physics.attach_rigid_body(obj.solid) elif isinstance(obj.solid, BulletGhostNode): self.physics.attach_ghost(obj.solid) if obj.node: if obj.solid: # If this is a solid visible object, create a new physics node and reparent the visual node to that. phys_node = self.render.attach_new_node(obj.solid) obj.node.reparent_to(phys_node) obj.node = phys_node else: # Otherwise just reparent the visual node to the root. obj.node.reparent_to(self.render) elif obj.solid: obj.node = self.render.attach_new_node(obj.solid) if obj.solid and obj.collide_bits is not None: obj.solid.set_into_collide_mask(obj.collide_bits) self.objects[obj.name] = obj # Let the object know it has been attached. obj.attached() return obj def get_incarn(self): return random.choice(self.incarnators) def create_hector(self, name=None): # TODO: get random incarn, start there h = self.attach(Hector(name)) h.move((0, 15, 0)) return h def set_ambient(self, color): """ Sets the ambient light to the given color. """ self.ambient.node().set_color(VBase4(*color)) def add_celestial(self, azimuth, elevation, color, intensity, radius, visible): """ Adds a celestial light source to the scene. If it is a visible celestial, also add a sphere model. """ if not self.camera: return location = Vec3(to_cartesian(azimuth, elevation, 1000.0 * 255.0 / 256.0)) if intensity: dlight = DirectionalLight('celestial') dlight.set_color((color[0] * intensity, color[1] * intensity, color[2] * intensity, 1.0)) node = self.render.attach_new_node(dlight) node.look_at(*(location * -1)) self.render.set_light(node) if visible: if radius <= 2.0: samples = 6 elif radius >= 36.0: samples = 40 else: samples = int(round(((1.5 * radius) * (2 / 3.0)) + 3.75)) celestial = Dome(radius * 1.5, samples, 2, color, 0, location, ((-(math.degrees(azimuth))), 90 + math.degrees(elevation), 0)) self.celestials.attach(celestial) def create_celestial_node(self): bounds = self.camera.node().get_lens().make_bounds() self.celestials = self.celestials.create_node() self.celestials.set_transparency(TransparencyAttrib.MAlpha) self.celestials.set_light_off() self.celestials.set_effect(CompassEffect.make(self.camera, CompassEffect.PPos)) self.celestials.node().set_bounds(bounds) self.celestials.node().set_final(True) self.celestials.reparent_to(self.render) def register_collider(self, obj): assert isinstance(obj, PhysicalObject) self.collidables.add(obj) def register_updater(self, obj): assert isinstance(obj, WorldObject) self.updatables.add(obj) def register_updater_later(self, obj): assert isinstance(obj, WorldObject) self.updatables_to_add.add(obj) def do_explosion(self, node, radius, force): center = node.get_pos(self.render); expl_body = BulletGhostNode("expl") expl_shape = BulletSphereShape(radius) expl_body.add_shape(expl_shape) expl_bodyNP = self.render.attach_new_node(expl_body) expl_bodyNP.set_pos(center) self.physics.attach_ghost(expl_body) result = self.physics.contact_test(expl_body) for contact in result.getContacts(): n0_name = contact.getNode0().get_name() n1_name = contact.getNode1().get_name() obj = None try: obj = self.objects[n1_name] except: break if n0_name == "expl" and n1_name not in EXPLOSIONS_DONT_PUSH and not n1_name.startswith('Walker'): # repeat contact test with just this pair of objects # otherwise all manifold point values will be the same # for all objects in original result real_c = self.physics.contact_test_pair(expl_body, obj.solid) mpoint = real_c.getContacts()[0].getManifoldPoint() distance = mpoint.getDistance() if distance < 0: if hasattr(obj, 'decompose'): obj.decompose() else: expl_vec = Vec3(mpoint.getPositionWorldOnA() - mpoint.getPositionWorldOnB()) expl_vec.normalize() magnitude = force * 1.0/math.sqrt(abs(radius - abs(distance))) obj.solid.set_active(True) obj.solid.apply_impulse(expl_vec*magnitude, mpoint.getLocalPointB()) if hasattr(obj, 'damage'): obj.damage(magnitude/5) self.physics.remove_ghost(expl_body) expl_bodyNP.detach_node() del(expl_body, expl_bodyNP) def do_plasma_push(self, plasma, node, energy): obj = None try: obj = self.objects[node] except: raise if node not in EXPLOSIONS_DONT_PUSH and not node.startswith('Walker'): if hasattr(obj, 'decompose'): obj.decompose() else: solid = obj.solid dummy_node = NodePath('tmp') dummy_node.set_hpr(plasma.hpr) dummy_node.set_pos(plasma.pos) f_vec = render.get_relative_vector(dummy_node, Vec3(0,0,1)) local_point = (obj.node.get_pos() - dummy_node.get_pos()) *-1 f_vec.normalize() solid.set_active(True) try: solid.apply_impulse(f_vec*(energy*35), Point3(local_point)) except: pass del(dummy_node) if hasattr(obj, 'damage'): obj.damage(energy*5) def update(self, task): """ Called every frame to update the physics, etc. """ dt = globalClock.getDt() for obj in self.updatables_to_add: self.updatables.add(obj) self.updatables_to_add = set() for obj in self.updatables: obj.update(dt) self.updatables -= self.garbage self.collidables -= self.garbage while True: if len(self.garbage) < 1: break; trash = self.garbage.pop() if(isinstance(trash.solid, BulletGhostNode)): self.physics.remove_ghost(trash.solid) if(isinstance(trash.solid, BulletRigidBodyNode)): self.physics.remove_rigid_body(trash.solid) if hasattr(trash, 'dead'): trash.dead() trash.node.remove_node() del(trash) self.physics.do_physics(dt) for obj in self.collidables: result = self.physics.contact_test(obj.node.node()) for contact in result.get_contacts(): obj1 = self.objects.get(contact.get_node0().get_name()) obj2 = self.objects.get(contact.get_node1().get_name()) if obj1 and obj2: # Check the collision bits to see if the two objects should collide. should_collide = obj1.collide_bits & obj2.collide_bits if not should_collide.is_zero(): pt = contact.get_manifold_point() if obj1 in self.collidables: obj1.collision(obj2, pt, True) if obj2 in self.collidables: obj2.collision(obj1, pt, False) return task.cont
class World(object): """ The World models basically everything about a map, including gravity, ambient light, the sky, and all map objects. """ def __init__(self, camera, debug=False, audio3d=None, client=None, server=None): self.objects = {} self.incarnators = [] self.collidables = set() self.updatables = set() self.updatables_to_add = set() self.garbage = set() self.render = NodePath('world') self.camera = camera self.audio3d = audio3d self.ambient = self._make_ambient() self.celestials = CompositeObject() self.sky = self.attach(Sky()) # Set up the physics world. TODO: let maps set gravity. self.gravity = DEFAULT_GRAVITY self.physics = BulletWorld() self.physics.set_gravity(self.gravity) self.debug = debug self.client = client self.server = server if debug: debug_node = BulletDebugNode('Debug') debug_node.show_wireframe(True) debug_node.show_constraints(True) debug_node.show_bounding_boxes(False) debug_node.show_normals(False) np = self.render.attach_new_node(debug_node) np.show() self.physics.set_debug_node(debug_node) def _make_ambient(self): alight = AmbientLight('ambient') alight.set_color(VBase4(*DEFAULT_AMBIENT_COLOR)) node = self.render.attach_new_node(alight) self.render.set_light(node) return node def attach(self, obj): assert hasattr(obj, 'world') and hasattr(obj, 'name') assert obj.name not in self.objects obj.world = self if obj.name.startswith('Incarnator'): self.incarnators.append(obj) if hasattr(obj, 'create_node') and hasattr(obj, 'create_solid'): # Let each object define it's own NodePath, then reparent them. obj.node = obj.create_node() obj.solid = obj.create_solid() if obj.solid: if isinstance(obj.solid, BulletRigidBodyNode): self.physics.attach_rigid_body(obj.solid) elif isinstance(obj.solid, BulletGhostNode): self.physics.attach_ghost(obj.solid) if obj.node: if obj.solid: # If this is a solid visible object, create a new physics node and reparent the visual node to that. phys_node = self.render.attach_new_node(obj.solid) obj.node.reparent_to(phys_node) obj.node = phys_node else: # Otherwise just reparent the visual node to the root. obj.node.reparent_to(self.render) elif obj.solid: obj.node = self.render.attach_new_node(obj.solid) if obj.solid and obj.collide_bits is not None: obj.solid.set_into_collide_mask(obj.collide_bits) self.objects[obj.name] = obj # Let the object know it has been attached. obj.attached() return obj def get_incarn(self): return random.choice(self.incarnators) def create_hector(self, name=None): # TODO: get random incarn, start there h = self.attach(Hector(name)) h.move((0, 15, 0)) return h def set_ambient(self, color): """ Sets the ambient light to the given color. """ self.ambient.node().set_color(VBase4(*color)) def add_celestial(self, azimuth, elevation, color, intensity, radius, visible): """ Adds a celestial light source to the scene. If it is a visible celestial, also add a sphere model. """ if not self.camera: return location = Vec3( to_cartesian(azimuth, elevation, 1000.0 * 255.0 / 256.0)) if intensity: dlight = DirectionalLight('celestial') dlight.set_color((color[0] * intensity, color[1] * intensity, color[2] * intensity, 1.0)) node = self.render.attach_new_node(dlight) node.look_at(*(location * -1)) self.render.set_light(node) if visible: if radius <= 2.0: samples = 6 elif radius >= 36.0: samples = 40 else: samples = int(round(((1.5 * radius) * (2 / 3.0)) + 3.75)) celestial = Dome( radius * 1.5, samples, 2, color, 0, location, ((-(math.degrees(azimuth))), 90 + math.degrees(elevation), 0)) self.celestials.attach(celestial) def create_celestial_node(self): bounds = self.camera.node().get_lens().make_bounds() self.celestials = self.celestials.create_node() self.celestials.set_transparency(TransparencyAttrib.MAlpha) self.celestials.set_light_off() self.celestials.set_effect( CompassEffect.make(self.camera, CompassEffect.PPos)) self.celestials.node().set_bounds(bounds) self.celestials.node().set_final(True) self.celestials.reparent_to(self.render) def register_collider(self, obj): assert isinstance(obj, PhysicalObject) self.collidables.add(obj) def register_updater(self, obj): assert isinstance(obj, WorldObject) self.updatables.add(obj) def register_updater_later(self, obj): assert isinstance(obj, WorldObject) self.updatables_to_add.add(obj) def do_explosion(self, node, radius, force): center = node.get_pos(self.render) expl_body = BulletGhostNode("expl") expl_shape = BulletSphereShape(radius) expl_body.add_shape(expl_shape) expl_bodyNP = self.render.attach_new_node(expl_body) expl_bodyNP.set_pos(center) self.physics.attach_ghost(expl_body) result = self.physics.contact_test(expl_body) for contact in result.getContacts(): n0_name = contact.getNode0().get_name() n1_name = contact.getNode1().get_name() obj = None try: obj = self.objects[n1_name] except: break if n0_name == "expl" and n1_name not in EXPLOSIONS_DONT_PUSH and not n1_name.startswith( 'Walker'): # repeat contact test with just this pair of objects # otherwise all manifold point values will be the same # for all objects in original result real_c = self.physics.contact_test_pair(expl_body, obj.solid) mpoint = real_c.getContacts()[0].getManifoldPoint() distance = mpoint.getDistance() if distance < 0: if hasattr(obj, 'decompose'): obj.decompose() else: expl_vec = Vec3(mpoint.getPositionWorldOnA() - mpoint.getPositionWorldOnB()) expl_vec.normalize() magnitude = force * 1.0 / math.sqrt( abs(radius - abs(distance))) obj.solid.set_active(True) obj.solid.apply_impulse(expl_vec * magnitude, mpoint.getLocalPointB()) if hasattr(obj, 'damage'): obj.damage(magnitude / 5) self.physics.remove_ghost(expl_body) expl_bodyNP.detach_node() del (expl_body, expl_bodyNP) def do_plasma_push(self, plasma, node, energy): obj = None try: obj = self.objects[node] except: raise if node not in EXPLOSIONS_DONT_PUSH and not node.startswith('Walker'): if hasattr(obj, 'decompose'): obj.decompose() else: solid = obj.solid dummy_node = NodePath('tmp') dummy_node.set_hpr(plasma.hpr) dummy_node.set_pos(plasma.pos) f_vec = render.get_relative_vector(dummy_node, Vec3(0, 0, 1)) local_point = (obj.node.get_pos() - dummy_node.get_pos()) * -1 f_vec.normalize() solid.set_active(True) try: solid.apply_impulse(f_vec * (energy * 35), Point3(local_point)) except: pass del (dummy_node) if hasattr(obj, 'damage'): obj.damage(energy * 5) def update(self, task): """ Called every frame to update the physics, etc. """ dt = globalClock.getDt() for obj in self.updatables_to_add: self.updatables.add(obj) self.updatables_to_add = set() for obj in self.updatables: obj.update(dt) self.updatables -= self.garbage self.collidables -= self.garbage while True: if len(self.garbage) < 1: break trash = self.garbage.pop() if (isinstance(trash.solid, BulletGhostNode)): self.physics.remove_ghost(trash.solid) if (isinstance(trash.solid, BulletRigidBodyNode)): self.physics.remove_rigid_body(trash.solid) if hasattr(trash, 'dead'): trash.dead() trash.node.remove_node() del (trash) self.physics.do_physics(dt) for obj in self.collidables: result = self.physics.contact_test(obj.node.node()) for contact in result.get_contacts(): obj1 = self.objects.get(contact.get_node0().get_name()) obj2 = self.objects.get(contact.get_node1().get_name()) if obj1 and obj2: # Check the collision bits to see if the two objects should collide. should_collide = obj1.collide_bits & obj2.collide_bits if not should_collide.is_zero(): pt = contact.get_manifold_point() if obj1 in self.collidables: obj1.collision(obj2, pt, True) if obj2 in self.collidables: obj2.collision(obj1, pt, False) return task.cont
class PandaPhysicsSystem(DelegateByNetmode, SignalListener): subclasses = {} def __init__(self): self.register_signals() self.world = BulletWorld() self.world.setGravity((0, 0, -9.81)) # # Seems that this does not function # on_contact_added = PythonCallbackObject(self._on_contact_added) # self.world.set_contact_added_callback(on_contact_added) # on_filter = PythonCallbackObject(self._filter_collision) # self.world.set_filter_callback(on_filter) self.listener = DirectObject() self.listener.accept('bullet-contact-added', self._on_contact_added) self.listener.accept('bullet-contact-destroyed', self._on_contact_removed) debug_node = BulletDebugNode('Debug') debug_node.showWireframe(True) debug_node.showConstraints(True) debug_node.showBoundingBoxes(False) debug_node.showNormals(False) self.debug_nodepath = render.attachNewNode(debug_node) self.world.set_debug_node(debug_node) self.debug_nodepath.show() def _get_contacts(self, node): test = self.world.contact_test(node) contacts = [] for contact in test.get_contacts(): if contact.get_node0() == node: manifold = contact.get_manifold_point() position = manifold.get_position_world_on_a() normal = None elif contact.get_node1() == node: manifold = contact.get_manifold_point() position = manifold.get_position_world_on_b() normal = None else: continue impulse = manifold.get_applied_impulse() contact_ = CollisionContact(position, normal, impulse) contacts.append(contact_) return contacts def _on_contact_added(self, node_a, node_b): if node_a.has_python_tag("on_contact_added"): callback = node_a.get_python_tag("on_contact_added") contacts = self._get_contacts(node_a) callback(node_b, contacts) if node_b.has_python_tag("on_contact_added"): callback = node_b.get_python_tag("on_contact_added") contacts = self._get_contacts(node_b) callback(node_a, contacts) def _on_contact_removed(self, node_a, node_b): if node_a.has_python_tag("on_contact_removed"): callback = node_a.get_python_tag("on_contact_removed") callback(node_b) if node_b.has_python_tag("on_contact_removed"): callback = node_b.get_python_tag("on_contact_removed") callback(node_a) def _filter_collision(self, filter_data): filter_data.set_collide(True) @RegisterPhysicsNode.on_global def register_node(self, node): self.world.attachRigidBody(node) node.set_python_tag("world", self.world) @DeregisterPhysicsNode.on_global def deregister_node(self, node): self.world.removeRigidBody(node) node.clear_python_tag("world") def update(self, delta_time): self.world.doPhysics(delta_time)
class PhysMgr(PhysFacade): __metaclass__ = Singleton def __init__(self): self.collision_objs = [] # objects to be processed self.__obj2coll = {} # obj: [(node, coll_time), ...] self.root = None self.__debug_np = None def init(self): self.collision_objs = [] self.__obj2coll = {} self.root = BulletWorld() self.root.setGravity((0, 0, -9.81)) debug_node = BulletDebugNode('Debug') debug_node.show_bounding_boxes(True) self.__debug_np = render.attach_new_node(debug_node) self.root.set_debug_node(self.__debug_np.node()) def start(self): eng.attach_obs(self.on_frame, 2) def on_frame(self): self.root.do_physics(globalClock.get_dt(), 10, 1 / 180.0) self.__do_collisions() def add_collision_obj(self, node): self.collision_objs += [node] def stop(self): self.root = None self.__debug_np.removeNode() eng.detach_obs(self.on_frame) def __process_contact(self, obj, node, to_clear): if node == obj: return obj in to_clear and to_clear.remove(obj) if node in [coll[0] for coll in self.__obj2coll[obj]]: return self.__obj2coll[obj] += [(node, globalClock.get_frame_time())] eng.event.notify('on_collision', obj, node.get_name()) def __do_collisions(self): to_clear = self.collision_objs[:] for obj in self.collision_objs: if not obj in self.__obj2coll: self.__obj2coll[obj] = [] result = self.root.contact_test(obj) for contact in result.get_contacts(): self.__process_contact(obj, contact.get_node0(), to_clear) self.__process_contact(obj, contact.get_node1(), to_clear) for obj in to_clear: for coll in self.__obj2coll[obj]: if globalClock.get_frame_time() - coll[1] > .25: self.__obj2coll[obj].remove(coll) def toggle_debug(self): is_hidden = self.__debug_np.is_hidden() (self.__debug_np.show if is_hidden else self.__debug_np.hide)() @staticmethod def find_geoms(model, name): # no need to be cached geoms = model.find_all_matches('**/+GeomNode') is_nm = lambda geom: geom.get_name().startswith(name) named_geoms = [geom for geom in geoms if is_nm(geom)] in_vec = [name in named_geom.get_name() for named_geom in named_geoms] indexes = [i for i, el in enumerate(in_vec) if el] return [named_geoms[i] for i in indexes]