19_ball_in_maze.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/env python
  2. import sys
  3. from direct.showbase.ShowBase import ShowBase
  4. from direct.showbase.InputStateGlobal import inputState
  5. from direct.interval.MetaInterval import Sequence
  6. from direct.interval.MetaInterval import Parallel
  7. from direct.interval.LerpInterval import LerpFunc
  8. from direct.interval.FunctionInterval import Func
  9. from direct.interval.FunctionInterval import Wait
  10. from panda3d.core import AmbientLight
  11. from panda3d.core import DirectionalLight
  12. from panda3d.core import Material
  13. from panda3d.bullet import BulletWorld
  14. from panda3d.bullet import BulletRigidBodyNode
  15. from panda3d.bullet import BulletGhostNode
  16. from panda3d.bullet import BulletDebugNode
  17. from panda3d.bullet import BulletHelper
  18. class Game(ShowBase):
  19. def __init__(self):
  20. ShowBase.__init__(self)
  21. base.set_background_color(0.1, 0.1, 0.8, 1)
  22. base.set_frame_rate_meter(True)
  23. base.cam.set_pos_hpr(0, 0, 25, 0, -90, 0)
  24. base.disable_mouse()
  25. # Input
  26. self.accept('escape', self.exitGame)
  27. self.accept('f1', base.toggle_wireframe)
  28. self.accept('f2', base.toggle_texture)
  29. self.accept('f3', self.toggle_debug)
  30. self.accept('f5', self.do_screenshot)
  31. # Setup scene 1: World
  32. self.debugNP = render.attach_new_node(BulletDebugNode('Debug'))
  33. self.debugNP.node().show_wireframe(True)
  34. self.debugNP.node().show_constraints(True)
  35. self.debugNP.node().show_bounding_boxes(True)
  36. self.debugNP.node().show_normals(True)
  37. self.debugNP.show()
  38. self.world = BulletWorld()
  39. self.world.set_gravity((0, 0, -9.81))
  40. self.world.set_debug_node(self.debugNP.node())
  41. # Setup scene 2: Ball
  42. #visNP = loader.load_model('models/ball.egg')
  43. visNP = loader.load_model('../ball-in-maze/models/ball.egg.pz')
  44. visNP.clear_model_nodes()
  45. bodyNPs = BulletHelper.from_collision_solids(visNP, True)
  46. self.ballNP = bodyNPs[0]
  47. self.ballNP.reparent_to(render)
  48. self.ballNP.node().set_mass(1.0)
  49. self.ballNP.set_pos(4, -4, 1)
  50. self.ballNP.node().set_deactivation_enabled(False)
  51. visNP.reparent_to(self.ballNP)
  52. # Setup scene 3: Maze
  53. visNP = loader.load_model('models/maze.egg')
  54. #visNP = loader.load_model('samples/ball-in-maze/models/maze.egg.pz')
  55. visNP.clear_model_nodes()
  56. visNP.reparent_to(render)
  57. self.holes = []
  58. self.maze = []
  59. self.mazeNP = visNP
  60. bodyNPs = BulletHelper.from_collision_solids(visNP, True);
  61. for bodyNP in bodyNPs:
  62. bodyNP.reparent_to(render)
  63. if isinstance(bodyNP.node(), BulletRigidBodyNode):
  64. bodyNP.node().set_mass(0.0)
  65. bodyNP.node().set_kinematic(True)
  66. self.maze.append(bodyNP)
  67. elif isinstance(bodyNP.node(), BulletGhostNode):
  68. self.holes.append(bodyNP)
  69. # Lighting and material for the ball
  70. ambientLight = AmbientLight('ambientLight')
  71. ambientLight.set_color((0.55, 0.55, 0.55, 1))
  72. directionalLight = DirectionalLight('directionalLight')
  73. directionalLight.set_direction((0, 0, -1))
  74. directionalLight.set_color((0.375, 0.375, 0.375, 1))
  75. directionalLight.set_specular_color((1, 1, 1, 1))
  76. self.ballNP.set_light(render.attach_new_node(ambientLight))
  77. self.ballNP.set_light(render.attach_new_node(directionalLight))
  78. m = Material()
  79. m.set_specular((1,1,1,1))
  80. m.set_shininess(96)
  81. self.ballNP.set_material(m, 1)
  82. # Startup
  83. self.start_game()
  84. def exitGame(self):
  85. sys.exit()
  86. def toggle_debug(self):
  87. if self.debugNP.is_hidden():
  88. self.debugNP.show()
  89. else:
  90. self.debugNP.hide()
  91. def do_screenshot(self):
  92. base.screenshot('Bullet')
  93. def start_game(self):
  94. self.ballNP.set_pos(4, -4, 1)
  95. self.ballNP.node().set_linear_velocity((0, 0, 0))
  96. self.ballNP.node().set_angular_velocity((0, 0, 0))
  97. # Mouse
  98. p = base.win.get_properties()
  99. base.win.move_pointer(0, int(p.get_x_size()/2), int(p.get_y_size()/2))
  100. # Add bodies and ghosts
  101. self.world.attach(self.ballNP.node())
  102. for bodyNP in self.maze:
  103. self.world.attach(bodyNP.node())
  104. for ghostNP in self.holes:
  105. self.world.attach(ghostNP.node())
  106. # Simulation task
  107. taskMgr.add(self.update_game, 'updateGame')
  108. def stop_game(self):
  109. # Remove bodies and ghosts
  110. self.world.remove(self.ballNP.node())
  111. for bodyNP in self.maze:
  112. self.world.remove(bodyNP.node())
  113. for ghostNP in self.holes:
  114. self.world.remove(ghostNP.node())
  115. # Simulation task
  116. taskMgr.remove('updateGame')
  117. def update_game(self, task):
  118. dt = globalClock.get_dt()
  119. # Get mouse position and tilt maze
  120. if base.mouseWatcherNode.hasMouse():
  121. mpos = base.mouseWatcherNode.get_mouse()
  122. hpr = (0, mpos.y * -10, mpos.x * 10)
  123. # Maze visual node
  124. self.mazeNP.set_hpr(hpr)
  125. # Maze body nodes
  126. for bodyNP in self.maze:
  127. bodyNP.set_hpr(hpr)
  128. # Update simulation
  129. self.world.do_physics(dt)
  130. # Check if ball is touching a hole
  131. for holeNP in self.holes:
  132. if holeNP.node().get_num_overlapping_nodes() > 2:
  133. if self.ballNP.node() in holeNP.node().get_overlapping_nodes():
  134. self.lose_game(holeNP)
  135. return task.cont
  136. def lose_game(self, holeNP):
  137. toPos = holeNP.node().get_shape_pos(0)
  138. self.stop_game()
  139. Sequence(
  140. Parallel(
  141. LerpFunc(self.ballNP.set_x, fromData = self.ballNP.get_x(),
  142. toData = toPos.get_x(), duration = .1),
  143. LerpFunc(self.ballNP.set_y, fromData = self.ballNP.get_y(),
  144. toData = toPos.get_y(), duration = .1),
  145. LerpFunc(self.ballNP.set_z, fromData = self.ballNP.get_z(),
  146. toData = self.ballNP.get_z() - .9, duration = .2)),
  147. Wait(1),
  148. Func(self.start_game)).start()
  149. game = Game()
  150. game.run()