actor.py 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. # coding: utf-8
  2. import typing
  3. import time
  4. import pyglet
  5. from PIL import Image
  6. from synergine2.config import Config
  7. from synergine2.simulation import Subject
  8. from synergine2_cocos2d.actor import Actor
  9. from synergine2_xyz.exception import UnknownAnimationIndex
  10. from opencombat.exception import UnknownWeapon
  11. from opencombat.exception import UnknownFiringAnimation
  12. from opencombat.gui.animation import ANIMATION_CRAWL
  13. from opencombat.gui.animation import ANIMATION_WALK
  14. from opencombat.gui.const import MODE_MAN_STAND_UP
  15. from opencombat.gui.const import MODE_MAN_CRAWLING
  16. from opencombat.gui.image import TileImageCacheManager
  17. from opencombat.gui.weapon import RIFFLE
  18. from opencombat.gui.weapon import WeaponImageApplier
  19. if typing.TYPE_CHECKING:
  20. from opencombat.gui.fire import GuiFiringEvent
  21. MODE_DEFAULT = 'MODE_DEFAULT'
  22. class BaseActor(Actor):
  23. position_matching = {
  24. ANIMATION_WALK: MODE_MAN_STAND_UP,
  25. ANIMATION_CRAWL: MODE_MAN_CRAWLING,
  26. }
  27. mode_image_paths = {
  28. MODE_DEFAULT: 'unknown.png',
  29. }
  30. modes = [
  31. MODE_DEFAULT,
  32. ]
  33. weapons_firing_image_scheme = {}
  34. weapon_image_scheme = {}
  35. def __init__(
  36. self,
  37. image_path: str,
  38. config: Config,
  39. subject: Subject,
  40. ) -> None:
  41. self._mode = MODE_MAN_STAND_UP
  42. self.weapon_image_applier = WeaponImageApplier(config, self)
  43. super().__init__(image_path, subject=subject, config=config)
  44. # Firing
  45. self.last_firing_time = 0
  46. self.firing_change_image_gap = 0.05 # seconds
  47. def get_image_cache_manager(self) -> TileImageCacheManager:
  48. return TileImageCacheManager(self, self.config)
  49. def get_default_mode(self) -> str:
  50. return MODE_DEFAULT
  51. def get_mode_image_path(self, mode: str) -> str:
  52. return self.mode_image_paths[mode]
  53. def get_modes(self) -> typing.List[str]:
  54. return self.modes
  55. @property
  56. def mode(self) -> str:
  57. # FIXME: When man is moving (crawling for example), must change mode
  58. # and man must stay "crawled"
  59. return self._mode
  60. @property
  61. def weapons(self) -> typing.List[str]:
  62. return []
  63. def get_default_appliable_images(self) -> typing.List[Image.Image]:
  64. if not self.weapons:
  65. return []
  66. return [
  67. self.weapon_image_applier.get_image_for_weapon(
  68. self.mode,
  69. self.weapons[0], # FIXME
  70. )
  71. ]
  72. def get_animation_appliable_images(
  73. self,
  74. animation_name: str,
  75. animation_position: int,
  76. ) -> typing.List[Image.Image]:
  77. if not self.weapons:
  78. return []
  79. position = self.position_matching[animation_name]
  80. try:
  81. return [
  82. self.weapon_image_applier.get_animation_image_for_weapon(
  83. position,
  84. self.weapons[0],
  85. animation_position,
  86. )
  87. ]
  88. except UnknownWeapon:
  89. return []
  90. def firing(self, firing: 'GuiFiringEvent') -> None:
  91. # FIXME: move some code ?
  92. now = time.time()
  93. if now - self.last_firing_time >= self.firing_change_image_gap:
  94. self.last_firing_time = now
  95. firing.increment_animation_index()
  96. try:
  97. image = self.image_cache_manager.firing_cache.get(
  98. mode=self.mode,
  99. weapon=firing.weapon,
  100. position=firing.animation_index,
  101. )
  102. except UnknownAnimationIndex:
  103. image = self.image_cache_manager.firing_cache.get(
  104. mode=self.mode,
  105. weapon=firing.weapon,
  106. position=0,
  107. )
  108. firing.reset_animation_index()
  109. except UnknownFiringAnimation as exc:
  110. self.logger.error(
  111. 'No firing animation for actor {}({}): {}'.format(
  112. self.__class__.__name__,
  113. str(self.subject.id),
  114. str(exc),
  115. )
  116. )
  117. return # There is no firing animation defined
  118. # FIXME cache: prepare before firing
  119. import uuid
  120. tmp_path = '/tmp/{}.png'.format(str(uuid.uuid4()))
  121. image.save(tmp_path)
  122. pyglet_image = pyglet.image.load(tmp_path)
  123. self.update_image(pyglet_image.get_texture())
  124. class Man(BaseActor):
  125. animation_image_paths = {
  126. ANIMATION_WALK: [
  127. 'actors/man.png',
  128. 'actors/man_w1.png',
  129. 'actors/man_w2.png',
  130. 'actors/man_w3.png',
  131. 'actors/man_w4.png',
  132. 'actors/man_w5.png',
  133. 'actors/man_w6.png',
  134. 'actors/man_w7.png',
  135. ],
  136. ANIMATION_CRAWL: [
  137. 'actors/man_c1.png',
  138. 'actors/man_c2.png',
  139. 'actors/man_c3.png',
  140. 'actors/man_c4.png',
  141. ]
  142. }
  143. modes = [
  144. MODE_MAN_STAND_UP,
  145. MODE_MAN_CRAWLING,
  146. ]
  147. mode_image_paths = {
  148. MODE_MAN_STAND_UP: 'actors/man.png',
  149. MODE_MAN_CRAWLING: 'actors/man_c1.png',
  150. }
  151. weapon_image_scheme = {
  152. MODE_MAN_STAND_UP: {
  153. RIFFLE: [
  154. 'actors/man_weap1.png'
  155. ],
  156. },
  157. MODE_MAN_CRAWLING: {
  158. RIFFLE: [
  159. 'actors/man_c1_weap1.png',
  160. 'actors/man_c2_weap1.png',
  161. 'actors/man_c3_weap1.png',
  162. 'actors/man_c4_weap1.png',
  163. ],
  164. }
  165. }
  166. weapons_firing_image_scheme = {
  167. MODE_MAN_STAND_UP: {
  168. RIFFLE: [
  169. 'actors/man_weap1_firing1.png',
  170. 'actors/man_weap1_firing2.png',
  171. 'actors/man_weap1_firing3.png',
  172. ],
  173. },
  174. }
  175. def __init__(
  176. self,
  177. config: Config,
  178. subject: Subject,
  179. ) -> None:
  180. super().__init__('actors/man.png', subject=subject, config=config)
  181. @property
  182. def weapons(self) -> typing.List[str]:
  183. # TODO BS 2018-01-26: Will be managed by complex part of code
  184. return [RIFFLE]
  185. def get_default_mode(self) -> str:
  186. return MODE_MAN_STAND_UP
  187. class HeavyVehicle(BaseActor):
  188. animation_image_paths = {
  189. ANIMATION_WALK: [
  190. 'actors/tank1.png',
  191. ],
  192. ANIMATION_CRAWL: [
  193. 'actors/tank1.png',
  194. ]
  195. }
  196. mode_image_paths = {
  197. MODE_DEFAULT: 'actors/tank1.png',
  198. }
  199. def __init__(
  200. self,
  201. config: Config,
  202. subject: Subject,
  203. ) -> None:
  204. super().__init__('actors/tank1.png', subject=subject, config=config)
  205. @property
  206. def weapons(self) -> typing.List[str]:
  207. # TODO BS 2018-01-26: Will be managed by complex part of code
  208. return [RIFFLE]