base.py 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. # coding: utf-8
  2. import os
  3. import random
  4. import typing
  5. import pyglet
  6. from pyglet.window import key
  7. from cocos.actions import MoveTo as BaseMoveTo
  8. from cocos.audio.pygame.mixer import Sound
  9. from sandbox.tile.user_action import UserAction
  10. from synergine2.config import Config
  11. from synergine2.log import SynergineLogger
  12. from synergine2.terminals import Terminal
  13. from synergine2_cocos2d.actions import MoveTo
  14. from synergine2_cocos2d.animation import ANIMATION_CRAWL
  15. from synergine2_cocos2d.animation import ANIMATION_WALK
  16. from synergine2_cocos2d.animation import Animate
  17. from synergine2_cocos2d.gl import draw_line
  18. from synergine2_cocos2d.gui import EditLayer as BaseEditLayer
  19. from synergine2_cocos2d.gui import TMXGui
  20. from synergine2_cocos2d.layer import LayerManager
  21. from synergine2_xyz.move.simulation import FinishMoveEvent
  22. from synergine2_xyz.move.simulation import StartMoveEvent
  23. from synergine2_xyz.physics import Physics
  24. from synergine2_xyz.utils import get_angle
  25. from sandbox.tile.simulation.event import NewVisibleOpponent
  26. from sandbox.tile.simulation.event import NoLongerVisibleOpponent
  27. from sandbox.tile.simulation.event import FireEvent
  28. from sandbox.tile.simulation.event import DieEvent
  29. class EditLayer(BaseEditLayer):
  30. def __init__(self, *args, **kwargs) -> None:
  31. super().__init__(*args, **kwargs)
  32. def _on_key_press(self, k, m):
  33. if self.selection:
  34. if k == key.M:
  35. self.user_action_pending = UserAction.ORDER_MOVE
  36. if k == key.R:
  37. self.user_action_pending = UserAction.ORDER_MOVE_FAST
  38. if k == key.C:
  39. self.user_action_pending = UserAction.ORDER_MOVE_CRAWL
  40. if k == key.F:
  41. self.user_action_pending = UserAction.ORDER_FIRE
  42. class TileLayerManager(LayerManager):
  43. edit_layer_class = EditLayer
  44. # TODO: Move into synergine2cocos2d
  45. class AudioLibrary(object):
  46. sound_file_paths = {
  47. 'gunshot_default': '204010__duckduckpony__homemade-gunshot-2.ogg',
  48. }
  49. def __init__(self, sound_dir_path: str) -> None:
  50. self._sound_dir_path = sound_dir_path
  51. self._sounds = {}
  52. def get_sound(self, name: str) -> Sound:
  53. if name not in self._sounds:
  54. sound_file_name = self.sound_file_paths[name]
  55. self._sounds[name] = Sound(os.path.join(self._sound_dir_path, sound_file_name))
  56. return self._sounds[name]
  57. class Game(TMXGui):
  58. layer_manager_class = TileLayerManager
  59. def __init__(
  60. self,
  61. config: Config,
  62. logger: SynergineLogger,
  63. terminal: Terminal,
  64. physics: Physics,
  65. read_queue_interval: float = 1 / 60.0,
  66. map_dir_path: str=None,
  67. ):
  68. super().__init__(
  69. config,
  70. logger,
  71. terminal,
  72. physics=physics,
  73. read_queue_interval=read_queue_interval,
  74. map_dir_path=map_dir_path,
  75. )
  76. self.sound_lib = AudioLibrary('sandbox/tile/sounds/')
  77. self.terminal.register_event_handler(
  78. FinishMoveEvent,
  79. self.set_subject_position,
  80. )
  81. self.terminal.register_event_handler(
  82. StartMoveEvent,
  83. self.start_move_subject,
  84. )
  85. self.terminal.register_event_handler(
  86. NewVisibleOpponent,
  87. self.new_visible_opponent,
  88. )
  89. self.terminal.register_event_handler(
  90. NoLongerVisibleOpponent,
  91. self.no_longer_visible_opponent,
  92. )
  93. self.terminal.register_event_handler(
  94. FireEvent,
  95. self.fire_happen,
  96. )
  97. self.terminal.register_event_handler(
  98. DieEvent,
  99. self.subject_die,
  100. )
  101. # configs
  102. self.move_duration_ref = float(self.config.resolve('game.move.walk_ref_time'))
  103. self.move_fast_duration_ref = float(self.config.resolve('game.move.run_ref_time'))
  104. self.move_crawl_duration_ref = float(self.config.resolve('game.move.crawl_ref_time'))
  105. def before_run(self) -> None:
  106. from sandbox.tile.gui.move import MoveActorInteraction
  107. from sandbox.tile.gui.move import MoveFastActorInteraction
  108. from sandbox.tile.gui.move import MoveCrawlActorInteraction
  109. from sandbox.tile.gui.fire import FireActorInteraction
  110. self.layer_manager.interaction_manager.register(MoveActorInteraction, self.layer_manager)
  111. self.layer_manager.interaction_manager.register(MoveFastActorInteraction, self.layer_manager)
  112. self.layer_manager.interaction_manager.register(MoveCrawlActorInteraction, self.layer_manager)
  113. self.layer_manager.interaction_manager.register(FireActorInteraction, self.layer_manager)
  114. def set_subject_position(self, event: FinishMoveEvent):
  115. actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]
  116. new_world_position = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(event.to_position)
  117. actor.stop_actions((BaseMoveTo,))
  118. actor.set_position(*new_world_position)
  119. def start_move_subject(self, event: StartMoveEvent):
  120. actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]
  121. new_world_position = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(event.to_position)
  122. if event.gui_action == UserAction.ORDER_MOVE:
  123. animation = ANIMATION_WALK
  124. cycle_duration = 2
  125. move_duration = self.move_duration_ref
  126. elif event.gui_action == UserAction.ORDER_MOVE_FAST:
  127. animation = ANIMATION_WALK
  128. cycle_duration = 0.5
  129. move_duration = self.move_fast_duration_ref
  130. elif event.gui_action == UserAction.ORDER_MOVE_CRAWL:
  131. animation = ANIMATION_CRAWL
  132. cycle_duration = 2
  133. move_duration = self.move_crawl_duration_ref
  134. else:
  135. raise NotImplementedError()
  136. move_action = MoveTo(new_world_position, move_duration)
  137. actor.do(move_action)
  138. actor.do(Animate(animation, duration=move_duration, cycle_duration=cycle_duration))
  139. actor.rotation = get_angle(event.from_position, event.to_position)
  140. def new_visible_opponent(self, event: NewVisibleOpponent):
  141. self.visible_or_no_longer_visible_opponent(event, (153, 0, 153))
  142. def no_longer_visible_opponent(self, event: NoLongerVisibleOpponent):
  143. self.visible_or_no_longer_visible_opponent(event, (255, 102, 0))
  144. def visible_or_no_longer_visible_opponent(
  145. self,
  146. event: typing.Union[NoLongerVisibleOpponent, NewVisibleOpponent],
  147. line_color,
  148. ) -> None:
  149. if self.layer_manager.debug:
  150. observer_actor = self.layer_manager.subject_layer.subjects_index[event.observer_subject_id]
  151. observed_actor = self.layer_manager.subject_layer.subjects_index[event.observed_subject_id]
  152. observer_pixel_position = self.layer_manager.scrolling_manager.world_to_screen(
  153. *self.layer_manager.grid_manager.get_pixel_position_of_grid_position(
  154. observer_actor.subject.position,
  155. )
  156. )
  157. observed_pixel_position = self.layer_manager.scrolling_manager.world_to_screen(
  158. *self.layer_manager.grid_manager.get_pixel_position_of_grid_position(
  159. observed_actor.subject.position,
  160. )
  161. )
  162. def draw_visible_opponent():
  163. draw_line(
  164. observer_pixel_position,
  165. observed_pixel_position,
  166. line_color,
  167. )
  168. # TODO: Not in edit layer !
  169. self.layer_manager.edit_layer.append_callback(draw_visible_opponent, 1.0)
  170. def fire_happen(self, event: FireEvent) -> None:
  171. # TODO: Not in edit layer !
  172. shooter_actor = self.layer_manager.subject_layer.subjects_index[event.shooter_subject_id]
  173. shooter_pixel_position = self.layer_manager.scrolling_manager.world_to_screen(
  174. *self.layer_manager.grid_manager.get_pixel_position_of_grid_position(
  175. shooter_actor.subject.position,
  176. )
  177. )
  178. fire_to_pixel_position = self.layer_manager.scrolling_manager.world_to_screen(
  179. *self.layer_manager.grid_manager.get_pixel_position_of_grid_position(
  180. event.target_position,
  181. )
  182. )
  183. def gunshot_trace():
  184. draw_line(
  185. shooter_pixel_position,
  186. fire_to_pixel_position,
  187. color=(255, 0, 0),
  188. )
  189. def gunshot_sound():
  190. self.sound_lib.get_sound('gunshot_default').play()
  191. # To avoid all in same time
  192. delay = random.uniform(0.0, 0.6)
  193. self.layer_manager.edit_layer.append_callback(gunshot_trace, duration=0.1, delay=delay)
  194. self.layer_manager.edit_layer.append_callback(gunshot_sound, duration=0.0, delay=delay)
  195. def subject_die(self, event: DieEvent) -> None:
  196. killed_actor = self.layer_manager.subject_layer.subjects_index[event.shoot_subject_id]
  197. dead_image = pyglet.resource.image('maps/003/actors/man_d1.png')
  198. killed_actor.update_image(dead_image)
  199. killed_actor.freeze()