physics.py 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. # coding: utf-8
  2. import typing
  3. from dijkstar import Graph
  4. from dijkstar import find_path
  5. from synergine2.config import Config
  6. from synergine2.share import shared
  7. from synergine2_xyz.map import TMXMap, XYZTile
  8. from synergine2_xyz.subjects import XYZSubject
  9. from synergine2_xyz.xyz import get_neighbor_positions
  10. class MoveCostComputer(object):
  11. def __init__(
  12. self,
  13. config: Config,
  14. ) -> None:
  15. self.config = config
  16. def for_subject(self, subject: XYZSubject):
  17. # TODO: Verifier ce que sont les parametres pour les nommer correctement
  18. def move_cost_func(previous_node: str, next_node: str, tile: XYZTile, unknown):
  19. return self.compute_move_cost(subject, tile, previous_node, next_node, unknown)
  20. return move_cost_func
  21. def compute_move_cost(
  22. self,
  23. subject: XYZSubject,
  24. tile: XYZTile,
  25. previous_node: str,
  26. next_node: str,
  27. unknown,
  28. ) -> float:
  29. return 1.0
  30. class VisibilityMatrix(object):
  31. _matrixes = shared.create('matrixes', value=lambda: {}) # type: typing.Dict[str, typing.Dict[float, typing.List[typing.List[float]]]] # nopep8
  32. def initialize_empty_matrix(self, name: str, height: float, matrix_width: int, matrix_height: int) -> None:
  33. self._matrixes[name] = {}
  34. self._matrixes[name][height] = []
  35. for y in range(matrix_height):
  36. x_list = []
  37. for x in range(matrix_width):
  38. x_list.append(0.0)
  39. self._matrixes[name][height].append(x_list)
  40. def get_matrix(self, name: str, height: float) -> typing.List[typing.List[float]]:
  41. return self._matrixes[name][height]
  42. def update_matrix(self, name: str, height: float, x: int, y: int, value: float) -> None:
  43. matrix = self.get_matrix(name, height)
  44. matrix[y][x] = value
  45. # TODO: Test if working and needed ? This is not perf friendly ...
  46. # Force shared data update
  47. self._matrixes = dict(self._matrixes)
  48. class Physics(object):
  49. visibility_matrix = VisibilityMatrix
  50. move_cost_computer_class = MoveCostComputer
  51. def __init__(
  52. self,
  53. config: Config,
  54. ) -> None:
  55. self.config = config
  56. self.graph = Graph() # Graph of possible movements for dijkstar algorithm lib
  57. self.visibility_matrix = self.visibility_matrix()
  58. self.move_cost_computer = self.move_cost_computer_class(config)
  59. def load(self) -> None:
  60. pass
  61. def position_to_key(self, position: typing.Tuple[int, int]) -> str:
  62. return '{}.{}'.format(*position)
  63. def found_path(
  64. self,
  65. start: typing.Tuple[int, int],
  66. end: typing.Tuple[int, int],
  67. subject: XYZSubject,
  68. ) -> typing.List[typing.Tuple[int, int]]:
  69. start_key = self.position_to_key(start)
  70. end_key = self.position_to_key(end)
  71. found_path = find_path(self.graph, start_key, end_key, cost_func=self.move_cost_computer.for_subject(subject))
  72. regular_path = []
  73. for position in found_path[0][1:]:
  74. x, y = map(int, position.split('.'))
  75. regular_path.append((x, y))
  76. return regular_path
  77. class TMXPhysics(Physics):
  78. tmx_map_class = TMXMap
  79. def __init__(
  80. self,
  81. config: Config,
  82. map_file_path: str,
  83. ) -> None:
  84. super().__init__(config)
  85. self.map_file_path = map_file_path
  86. self.tmx_map = self.tmx_map_class(map_file_path)
  87. def load(self) -> None:
  88. self.load_graph_from_map(self.map_file_path)
  89. def load_graph_from_map(self, map_file_path: str) -> None:
  90. # TODO: tmx_map contient tout en cache, faire le dessous en exploitant tmx_map.
  91. for y in range(self.tmx_map.height):
  92. for x in range(self.tmx_map.width):
  93. position = self.position_to_key((x, y))
  94. for neighbor_position in get_neighbor_positions((x, y)):
  95. neighbor = '{}.{}'.format(*neighbor_position)
  96. neighbor_x, neighbor_y = neighbor_position
  97. if neighbor_x > self.tmx_map.width-1 or neighbor_x < 0:
  98. continue
  99. if neighbor_y > self.tmx_map.height-1 or neighbor_y < 0:
  100. continue
  101. # Note: movement consider future tile properties
  102. to_tile = self.tmx_map.layer_tiles('terrain')[neighbor]
  103. # Note: Voir https://pypi.python.org/pypi/Dijkstar/2.2
  104. self.graph.add_edge(position, neighbor, to_tile)