08_contacts.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #!/usr/bin/env python
  2. #from panda3d.core import load_prc_file_data
  3. #load_prc_file_data('', 'bullet-enable-contact-events true')
  4. import sys
  5. from direct.showbase.ShowBase import ShowBase
  6. from direct.showbase.InputStateGlobal import inputState
  7. from panda3d.core import AmbientLight
  8. from panda3d.core import DirectionalLight
  9. from panda3d.core import LVector3
  10. from panda3d.core import LPoint3
  11. from panda3d.core import TransformState
  12. from panda3d.core import BitMask32
  13. from panda3d.core import NodePath
  14. from panda3d.bullet import BulletWorld
  15. from panda3d.bullet import BulletDebugNode
  16. from panda3d.bullet import BulletPlaneShape
  17. from panda3d.bullet import BulletBoxShape
  18. from panda3d.bullet import BulletSphereShape
  19. from panda3d.bullet import BulletRigidBodyNode
  20. class Game(ShowBase):
  21. def __init__(self):
  22. ShowBase.__init__(self)
  23. base.set_background_color(0.1, 0.1, 0.8, 1)
  24. base.set_frame_rate_meter(True)
  25. base.cam.set_pos(0, -20, 4)
  26. base.cam.look_at(0, 0, 0)
  27. # Light
  28. alight = AmbientLight('ambientLight')
  29. alight.set_color((0.5, 0.5, 0.5, 1))
  30. alightNP = render.attach_new_node(alight)
  31. dlight = DirectionalLight('directionalLight')
  32. dlight.set_direction((1, 1, -1))
  33. dlight.set_color((0.7, 0.7, 0.7, 1))
  34. dlightNP = render.attach_new_node(dlight)
  35. render.clear_light()
  36. render.set_light(alightNP)
  37. render.set_light(dlightNP)
  38. # Input
  39. self.accept('escape', self.do_exit)
  40. self.accept('r', self.do_reset)
  41. self.accept('f1', base.toggle_wireframe)
  42. self.accept('f2', base.toggle_texture)
  43. self.accept('f3', self.toggle_debug)
  44. self.accept('f5', self.do_screenshot)
  45. inputState.watchWithModifiers('forward', 'w')
  46. inputState.watchWithModifiers('left', 'a')
  47. inputState.watchWithModifiers('reverse', 's')
  48. inputState.watchWithModifiers('right', 'd')
  49. inputState.watchWithModifiers('turnLeft', 'q')
  50. inputState.watchWithModifiers('turnRight', 'e')
  51. # Task
  52. taskMgr.add(self.update, 'updateWorld')
  53. # Physics
  54. self.setup()
  55. def do_exit(self):
  56. self.cleanup()
  57. sys.exit(1)
  58. def do_reset(self):
  59. self.cleanup()
  60. self.setup()
  61. def toggle_debug(self):
  62. if self.debugNP.is_hidden():
  63. self.debugNP.show()
  64. else:
  65. self.debugNP.hide()
  66. def do_screenshot(self):
  67. base.screenshot('Bullet')
  68. def process_input(self, dt):
  69. if not self.box:
  70. return
  71. force = LVector3(0, 0, 0)
  72. torque = LVector3(0, 0, 0)
  73. if inputState.isSet('forward'): force.y = 1.0
  74. if inputState.isSet('reverse'): force.y = -1.0
  75. if inputState.isSet('left'): force.x = -1.0
  76. if inputState.isSet('right'): force.x = 1.0
  77. if inputState.isSet('turnLeft'): torque.z = 1.0
  78. if inputState.isSet('turnRight'): torque.z = -1.0
  79. force *= 30.0
  80. torque *= 10.0
  81. self.box.set_active(True)
  82. self.box.apply_central_force(force)
  83. self.box.apply_torque(torque)
  84. def process_contacts(self):
  85. if not self.box or not self.sphere:
  86. return
  87. result = self.world.contact_test_pair(self.box, self.sphere)
  88. #result = self.world.contact_test(self.box)
  89. #print '-->', result.get_num_contacts()
  90. for contact in result.get_contacts():
  91. cp = contact.get_manifold_point()
  92. node0 = contact.get_node0()
  93. node1 = contact.get_node1()
  94. print(node0.get_name(), node1.get_name(), cp.get_local_point_a())
  95. #print(contact.get_node0(), cp.get_position_world_on_a())
  96. #print(contact.get_idx0(), contact.get_idx1(), \
  97. # contact.get_part_id0(), contact.get_part_id1())
  98. self.remove_node(node1)
  99. def remove_node(self, node):
  100. self.world.remove(node)
  101. if node == self.sphere: self.sphere = None
  102. if node == self.box: self.box = None
  103. np = NodePath(node)
  104. np.remove_node()
  105. def update(self, task):
  106. dt = globalClock.get_dt()
  107. self.process_input(dt)
  108. self.world.do_physics(dt, 10, 0.008)
  109. self.process_contacts()
  110. return task.cont
  111. def cleanup(self):
  112. self.world = None
  113. self.worldNP.remove_node()
  114. #def on_contact_added(self, node1, node2):
  115. # print('contact added:', node1, node2)
  116. #def on_contact_destroyed(self, node1, node2):
  117. # print('contact destroyed:', node1, node2)
  118. def setup(self):
  119. self.worldNP = render.attach_new_node('World')
  120. # World
  121. self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
  122. self.debugNP.show()
  123. self.world = BulletWorld()
  124. self.world.set_gravity((0, 0, -9.81))
  125. self.world.set_debug_node(self.debugNP.node())
  126. # Plane
  127. shape = BulletPlaneShape((0, 0, 1), 0)
  128. np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
  129. np.node().add_shape(shape)
  130. np.set_pos(0, 0, -1)
  131. np.set_collide_mask(BitMask32.all_on())
  132. self.world.attach(np.node())
  133. # Box
  134. shape = BulletBoxShape((0.5, 0.5, 0.5))
  135. np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box'))
  136. np.node().set_mass(1.0)
  137. np.node().add_shape(shape)
  138. np.node().set_deactivation_enabled(False)
  139. np.set_pos(2, 0, 4)
  140. np.set_collide_mask(BitMask32.all_on())
  141. self.world.attach(np.node())
  142. visualNP = loader.load_model('models/box.egg')
  143. visualNP.reparent_to(np)
  144. self.box = np.node()
  145. # Sphere
  146. shape = BulletSphereShape(0.6)
  147. np = self.worldNP.attach_new_node(BulletRigidBodyNode('Sphere'))
  148. np.node().set_mass(1.0)
  149. np.node().add_shape(shape)
  150. np.set_pos(-2, 0, 4)
  151. np.set_collide_mask(BitMask32.all_on())
  152. self.world.attach(np.node())
  153. self.sphere = np.node()
  154. ## Enable contact reporting
  155. #self.accept('bullet-contact-added', self.on_contact_added)
  156. #self.accept('bullet-contact-destroyed', self.on_contact_destroyed)
  157. #self.box.notify_collisions(True)
  158. game = Game()
  159. game.run()