Browse Source

Fire cursor drawing

Bastien Sevajol 6 years ago
parent
commit
7d14642de4

+ 13 - 0
sandbox/tile/gui/base.py View File

3
 from pyglet.window import key
3
 from pyglet.window import key
4
 
4
 
5
 from cocos.actions import MoveTo as BaseMoveTo
5
 from cocos.actions import MoveTo as BaseMoveTo
6
+from sandbox.tile.simulation.physics import TilePhysics
6
 from sandbox.tile.user_action import UserAction
7
 from sandbox.tile.user_action import UserAction
7
 from synergine2.config import Config
8
 from synergine2.config import Config
8
 from synergine2.log import SynergineLogger
9
 from synergine2.log import SynergineLogger
17
 from synergine2_cocos2d.layer import LayerManager
18
 from synergine2_cocos2d.layer import LayerManager
18
 from synergine2_xyz.move.simulation import FinishMoveEvent
19
 from synergine2_xyz.move.simulation import FinishMoveEvent
19
 from synergine2_xyz.move.simulation import StartMoveEvent
20
 from synergine2_xyz.move.simulation import StartMoveEvent
21
+from synergine2_xyz.physics import Matrixes
20
 from synergine2_xyz.utils import get_angle
22
 from synergine2_xyz.utils import get_angle
21
 
23
 
22
 
24
 
23
 class EditLayer(BaseEditLayer):
25
 class EditLayer(BaseEditLayer):
26
+    def __init__(self, *args, **kwargs) -> None:
27
+        super().__init__(*args, **kwargs)
28
+        self.matrixes = Matrixes()
29
+        self.physics = TilePhysics(
30
+            self.config,
31
+            map_file_path='sandbox/tile/maps/003/003.tmx',  # FIXME: HARDCODED
32
+        )
33
+
24
     def _on_key_press(self, k, m):
34
     def _on_key_press(self, k, m):
25
         if self.selection:
35
         if self.selection:
26
             if k == key.M:
36
             if k == key.M:
29
                 self.user_action_pending = UserAction.ORDER_MOVE_FAST
39
                 self.user_action_pending = UserAction.ORDER_MOVE_FAST
30
             if k == key.C:
40
             if k == key.C:
31
                 self.user_action_pending = UserAction.ORDER_MOVE_CRAWL
41
                 self.user_action_pending = UserAction.ORDER_MOVE_CRAWL
42
+            if k == key.F:
43
+                self.user_action_pending = UserAction.ORDER_FIRE
32
 
44
 
33
 
45
 
34
 class TileLayerManager(LayerManager):
46
 class TileLayerManager(LayerManager):
78
         self.layer_manager.interaction_manager.register(MoveActorInteraction, self.layer_manager)
90
         self.layer_manager.interaction_manager.register(MoveActorInteraction, self.layer_manager)
79
         self.layer_manager.interaction_manager.register(MoveFastActorInteraction, self.layer_manager)
91
         self.layer_manager.interaction_manager.register(MoveFastActorInteraction, self.layer_manager)
80
         self.layer_manager.interaction_manager.register(MoveCrawlActorInteraction, self.layer_manager)
92
         self.layer_manager.interaction_manager.register(MoveCrawlActorInteraction, self.layer_manager)
93
+        self.layer_manager.interaction_manager.register(FireActorInteraction, self.layer_manager)
81
 
94
 
82
     def set_subject_position(self, event: FinishMoveEvent):
95
     def set_subject_position(self, event: FinishMoveEvent):
83
         actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]
96
         actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]

+ 67 - 0
sandbox/tile/gui/fire.py View File

1
+# coding: utf-8
2
+import typing
3
+
4
+from sandbox.tile.simulation.fire import RequestFireBehaviour
5
+from synergine2_cocos2d.interaction import BaseActorInteraction
6
+from sandbox.tile.user_action import UserAction
7
+from synergine2.simulation import SimulationBehaviour
8
+from synergine2_cocos2d.actor import Actor
9
+from synergine2_cocos2d.gl import draw_line
10
+
11
+
12
+class BaseFireActorInteraction(BaseActorInteraction):
13
+    gui_action = None
14
+    color = None
15
+    not_visible_color = (0, 0, 0)
16
+    request_move_behaviour_class = RequestFireBehaviour
17
+
18
+    def draw_pending(self) -> None:
19
+        for actor in self.layer_manager.edit_layer.selection:
20
+            actor_grid_position = self.layer_manager.grid_manager.get_grid_position(actor.position)
21
+            actor_pixel_position = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(
22
+                actor_grid_position,
23
+            )
24
+            mouse_grid_position = self.layer_manager.grid_manager.get_grid_position(
25
+                self.layer_manager.scrolling_manager.screen_to_world(
26
+                    *self.layer_manager.edit_layer.screen_mouse,
27
+                )
28
+            )
29
+            draw_to_pixel = self.layer_manager.edit_layer.screen_mouse
30
+
31
+            obstacle_grid_position = self.layer_manager.edit_layer.physics.get_visibility_obstacle(
32
+                subject=actor.subject,
33
+                to_position=mouse_grid_position,
34
+                matrixes=self.layer_manager.edit_layer.matrixes,
35
+                matrix_name='visibility',
36
+                opacity_property_name='opacity',
37
+            )
38
+            if obstacle_grid_position:
39
+                obstacle_pixel = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(
40
+                    obstacle_grid_position,
41
+                )
42
+                draw_to_pixel = obstacle_pixel
43
+
44
+                draw_line(
45
+                    obstacle_pixel,
46
+                    self.layer_manager.edit_layer.screen_mouse,
47
+                    self.not_visible_color,
48
+                )
49
+
50
+            draw_line(
51
+                self.layer_manager.scrolling_manager.world_to_screen(*actor_pixel_position),
52
+                draw_to_pixel,
53
+                self.color,
54
+            )
55
+
56
+    def get_behaviour(self, actor: Actor, mouse_grid_position) -> typing.Tuple[typing.Type[SimulationBehaviour], dict]:
57
+        raise NotImplementedError()
58
+        return self.request_move_behaviour_class, {
59
+            'subject_id': actor.subject.id,
60
+            'move_to': mouse_grid_position,
61
+            'gui_action': self.gui_action,
62
+        }
63
+
64
+
65
+class FireActorInteraction(BaseFireActorInteraction):
66
+    gui_action = UserAction.ORDER_FIRE
67
+    color = (255, 0, 0)

File diff suppressed because it is too large
+ 126 - 9
sandbox/tile/maps/003/003.tmx


+ 4 - 0
sandbox/tile/maps/003/terrain.tsx View File

6
    <property name="name" type="str" value="Grass"/>
6
    <property name="name" type="str" value="Grass"/>
7
    <property name="traversable_by_man" type="bool" value="true"/>
7
    <property name="traversable_by_man" type="bool" value="true"/>
8
    <property name="traversable_by_vehicle" type="bool" value="true"/>
8
    <property name="traversable_by_vehicle" type="bool" value="true"/>
9
+   <property name="opacity" type="float" value="0.0"/>
10
+   <property name="height" type="float" value="0.0"/>
9
   </properties>
11
   </properties>
10
  </tile>
12
  </tile>
11
  <tile id="1">
13
  <tile id="1">
13
    <property name="name" type="str" value="Wood wall"/>
15
    <property name="name" type="str" value="Wood wall"/>
14
    <property name="traversable_by_man" type="bool" value="false"/>
16
    <property name="traversable_by_man" type="bool" value="false"/>
15
    <property name="traversable_by_vehicle" type="bool" value="false"/>
17
    <property name="traversable_by_vehicle" type="bool" value="false"/>
18
+   <property name="opacity" type="float" value="100.0"/>
19
+   <property name="height" type="float" value="2.0"/>
16
   </properties>
20
   </properties>
17
  </tile>
21
  </tile>
18
 </tileset>
22
 </tileset>

+ 2 - 18
sandbox/tile/simulation/base.py View File

1
 # coding: utf-8
1
 # coding: utf-8
2
-import tmx
3
 
2
 
4
-from sandbox.tile.simulation.physics import TerrainTile
5
-from sandbox.tile.simulation.physics import TileMoveCostComputer
3
+from sandbox.tile.simulation.physics import TilePhysics
6
 from synergine2.config import Config
4
 from synergine2.config import Config
7
-from synergine2_xyz.map import TMXMap
8
 from synergine2_xyz.physics import Physics
5
 from synergine2_xyz.physics import Physics
9
-from synergine2_xyz.physics import TMXPhysics
10
 from synergine2_xyz.simulation import XYZSimulation
6
 from synergine2_xyz.simulation import XYZSimulation
11
-from synergine2_xyz.subjects import XYZSubjects
12
 from synergine2_xyz.subjects import XYZSubject
7
 from synergine2_xyz.subjects import XYZSubject
13
-
14
-
15
-class TileMap(TMXMap):
16
-    xyz_tile_class = TerrainTile
17
-
18
-    def get_default_tileset(self) -> tmx.Tileset:
19
-        return self.tmx_tilesets['terrain']
20
-
21
-
22
-class TilePhysics(TMXPhysics):
23
-    tmx_map_class = TileMap
24
-    move_cost_computer_class = TileMoveCostComputer
8
+from synergine2_xyz.subjects import XYZSubjects
25
 
9
 
26
 
10
 
27
 class TileStrategySimulation(XYZSimulation):
11
 class TileStrategySimulation(XYZSimulation):

+ 39 - 0
sandbox/tile/simulation/fire.py View File

1
+# coding: utf-8
2
+import typing
3
+
4
+from synergine2.config import Config
5
+from synergine2.simulation import SimulationBehaviour
6
+from synergine2.simulation import Simulation
7
+from synergine2.simulation import Event
8
+from synergine2.simulation import Intention
9
+from synergine2_xyz.simulation import XYZSimulation
10
+
11
+
12
+class FireIntention(Intention):
13
+    def __init__(
14
+        self,
15
+        to_position: typing.Tuple[int, int],
16
+        to_subject_id: int,
17
+        gui_action: typing.Any,
18
+    ) -> None:
19
+        self.to_position = to_position
20
+        self.to_subject_id = to_subject_id
21
+        self.gui_action = gui_action
22
+
23
+
24
+class RequestFireBehaviour(SimulationBehaviour):
25
+    move_intention_class = FireIntention
26
+
27
+    def __init__(
28
+        self,
29
+        config: Config,
30
+        simulation: Simulation,
31
+    ):
32
+        super().__init__(config, simulation)
33
+        self.simulation = typing.cast(XYZSimulation, self.simulation)
34
+
35
+    def action(self, data) -> typing.List[Event]:
36
+        to_position = data['to_position']
37
+        to_subject_id = data['to_subject_id']
38
+
39
+        return []

+ 52 - 5
sandbox/tile/simulation/physics.py View File

1
 # coding: utf-8
1
 # coding: utf-8
2
-from synergine2_xyz.map import XYZTile
2
+import typing
3
+
4
+from sandbox.tile.simulation.tmx import TileMap
5
+from sandbox.tile.simulation.tmx import TerrainTile
6
+from synergine2_xyz.physics import Matrixes
3
 from synergine2_xyz.physics import MoveCostComputer
7
 from synergine2_xyz.physics import MoveCostComputer
8
+from synergine2_xyz.physics import TMXPhysics
9
+from synergine2_xyz.subjects import XYZSubject
4
 
10
 
5
 if False:
11
 if False:
6
     from sandbox.tile.simulation.base import BaseSubject
12
     from sandbox.tile.simulation.base import BaseSubject
7
 
13
 
8
 
14
 
9
-class TerrainTile(XYZTile):
10
-    pass
11
-
12
-
13
 class TileMoveCostComputer(MoveCostComputer):
15
 class TileMoveCostComputer(MoveCostComputer):
14
     def compute_move_cost(
16
     def compute_move_cost(
15
         self,
17
         self,
26
             return 100
28
             return 100
27
 
29
 
28
         return 1.0
30
         return 1.0
31
+
32
+
33
+class TilePhysics(TMXPhysics):
34
+    tmx_map_class = TileMap
35
+    move_cost_computer_class = TileMoveCostComputer
36
+    matrixes_configuration = {
37
+        'visibility': [
38
+            'height',
39
+            'opacity',
40
+        ]
41
+    }
42
+
43
+    def get_visibility_obstacle(
44
+        self,
45
+        subject: XYZSubject,
46
+        to_position: typing.Tuple[int, int],
47
+        matrixes: Matrixes,
48
+        matrix_name: str,
49
+        opacity_property_name: str='opacity',
50
+    ) -> typing.Union[None, typing.Tuple[int, int]]:
51
+        """
52
+        Return grid position obstacle if any between given subject and given to_position
53
+        :param subject: Subject observer
54
+        :param to_position: position to observe
55
+        :param matrixes: Matrixes instance
56
+        :param matrix_name: matrix name to use
57
+        :param opacity_property_name: name of property containing opacity property
58
+        :return: obstacle grid position or None if not
59
+        """
60
+        from_x, from_y = subject.position
61
+        path_positions = matrixes.get_path_positions(from_=(from_x, from_y), to=to_position)
62
+        path_opacities = matrixes.get_values_for_path(
63
+            matrix_name,
64
+            path_positions=path_positions,
65
+            value_name=opacity_property_name,
66
+        )
67
+
68
+        # FIXME: This algo is not ok, it is for test
69
+        actual_opacity = 0
70
+        for i, path_opacity in enumerate(path_opacities):
71
+            actual_opacity += path_opacity
72
+            if actual_opacity >= 100:
73
+                return path_positions[i]
74
+
75
+        return None

+ 16 - 0
sandbox/tile/simulation/tmx.py View File

1
+# coding: utf-8
2
+import tmx
3
+
4
+from synergine2_xyz.map import TMXMap
5
+from synergine2_xyz.map import XYZTile
6
+
7
+
8
+class TerrainTile(XYZTile):
9
+    pass
10
+
11
+
12
+class TileMap(TMXMap):
13
+    xyz_tile_class = TerrainTile
14
+
15
+    def get_default_tileset(self) -> tmx.Tileset:
16
+        return self.tmx_tilesets['terrain']

+ 1 - 0
sandbox/tile/user_action.py View File

6
     ORDER_MOVE = 'ORDER_MOVE'
6
     ORDER_MOVE = 'ORDER_MOVE'
7
     ORDER_MOVE_FAST = 'ORDER_MOVE_FAST'
7
     ORDER_MOVE_FAST = 'ORDER_MOVE_FAST'
8
     ORDER_MOVE_CRAWL = 'ORDER_MOVE_CRAWL'
8
     ORDER_MOVE_CRAWL = 'ORDER_MOVE_CRAWL'
9
+    ORDER_FIRE = 'ORDER_FIRE'

+ 7 - 3
synergine2_cocos2d/middleware.py View File

18
         self.map_dir_path = map_dir_path
18
         self.map_dir_path = map_dir_path
19
         self.tmx = None
19
         self.tmx = None
20
 
20
 
21
-    def init(self) -> None:
22
-        self.tmx = cocos.tiles.load(os.path.join(
21
+    def get_map_file_path(self) -> str:
22
+        return os.path.join(
23
             self.map_dir_path,
23
             self.map_dir_path,
24
             '{}.tmx'.format(os.path.basename(self.map_dir_path)),
24
             '{}.tmx'.format(os.path.basename(self.map_dir_path)),
25
-        ))
25
+        )
26
+
27
+    def init(self) -> None:
28
+        map_file_path = self.get_map_file_path()
29
+        self.tmx = cocos.tiles.load(map_file_path)
26
 
30
 
27
     def get_background_sprite(self) -> cocos.sprite.Sprite:
31
     def get_background_sprite(self) -> cocos.sprite.Sprite:
28
         raise NotImplementedError()
32
         raise NotImplementedError()

+ 33 - 5
synergine2_xyz/physics.py View File

8
 from synergine2.share import shared
8
 from synergine2.share import shared
9
 from synergine2_xyz.map import TMXMap, XYZTile
9
 from synergine2_xyz.map import TMXMap, XYZTile
10
 from synergine2_xyz.subjects import XYZSubject
10
 from synergine2_xyz.subjects import XYZSubject
11
+from synergine2_xyz.tmx_utils import fill_matrix
11
 from synergine2_xyz.utils import get_line_xy_path
12
 from synergine2_xyz.utils import get_line_xy_path
12
 from synergine2_xyz.xyz import get_neighbor_positions
13
 from synergine2_xyz.xyz import get_neighbor_positions
13
 
14
 
38
 
39
 
39
 class Matrixes(object):
40
 class Matrixes(object):
40
     _matrixes = shared.create('matrixes', value=lambda: {})  # type: typing.Dict[str, typing.List[typing.List[tuple]]]
41
     _matrixes = shared.create('matrixes', value=lambda: {})  # type: typing.Dict[str, typing.List[typing.List[tuple]]]
41
-
42
-    def __init__(self):
43
-        self._value_structures = {}  # type: typing.List[str]
42
+    _value_structures = shared.create('value_structures', value=lambda: {})  # type: typing.List[str]
44
 
43
 
45
     def initialize_empty_matrix(
44
     def initialize_empty_matrix(
46
         self,
45
         self,
75
     ) -> typing.List[typing.Tuple[int, int]]:
74
     ) -> typing.List[typing.Tuple[int, int]]:
76
         return get_line_xy_path(from_, to)
75
         return get_line_xy_path(from_, to)
77
 
76
 
78
-    def get_values_for_path(self, name: str, path_positions: typing.List[typing.Tuple[int, int]]):
77
+    def get_values_for_path(
78
+        self,
79
+        name: str,
80
+        path_positions: typing.List[typing.Tuple[int, int]],
81
+        value_name: str=None,
82
+    ):
79
         values = []
83
         values = []
84
+        value_name_position = None
85
+
86
+        if value_name:
87
+            value_name_position = self._value_structures[name].index(value_name)
88
+
80
         matrix = self.get_matrix(name)
89
         matrix = self.get_matrix(name)
81
         for path_position in path_positions:
90
         for path_position in path_positions:
82
             x, y = path_position
91
             x, y = path_position
83
-            values.append(matrix[y][x])
92
+            if value_name_position is None:
93
+                values.append(matrix[y][x])
94
+            else:
95
+                values.append(matrix[y][x][value_name_position])
84
         return values
96
         return values
85
 
97
 
86
     def get_value(self, matrix_name: str, x: int, y: int, value_name: str) -> float:
98
     def get_value(self, matrix_name: str, x: int, y: int, value_name: str) -> float:
129
 
141
 
130
 class TMXPhysics(Physics):
142
 class TMXPhysics(Physics):
131
     tmx_map_class = TMXMap
143
     tmx_map_class = TMXMap
144
+    matrixes_configuration = None  # type: typing.Dict[str, typing.List[str]]
132
 
145
 
133
     def __init__(
146
     def __init__(
134
         self,
147
         self,
138
         super().__init__(config)
151
         super().__init__(config)
139
         self.map_file_path = map_file_path
152
         self.map_file_path = map_file_path
140
         self.tmx_map = self.tmx_map_class(map_file_path)
153
         self.tmx_map = self.tmx_map_class(map_file_path)
154
+        self.matrixes = Matrixes()
141
 
155
 
142
     def load(self) -> None:
156
     def load(self) -> None:
143
         self.load_graph_from_map(self.map_file_path)
157
         self.load_graph_from_map(self.map_file_path)
158
+        self.load_matrixes_from_map()
144
 
159
 
145
     def load_graph_from_map(self, map_file_path: str) -> None:
160
     def load_graph_from_map(self, map_file_path: str) -> None:
146
         # TODO: tmx_map contient tout en cache, faire le dessous en exploitant tmx_map.
161
         # TODO: tmx_map contient tout en cache, faire le dessous en exploitant tmx_map.
162
                     to_tile = self.tmx_map.layer_tiles('terrain')[neighbor]
177
                     to_tile = self.tmx_map.layer_tiles('terrain')[neighbor]
163
                     # Note: Voir https://pypi.python.org/pypi/Dijkstar/2.2
178
                     # Note: Voir https://pypi.python.org/pypi/Dijkstar/2.2
164
                     self.graph.add_edge(position, neighbor, to_tile)
179
                     self.graph.add_edge(position, neighbor, to_tile)
180
+
181
+    def load_matrixes_from_map(self) -> None:
182
+        if not self.matrixes_configuration:
183
+            return
184
+
185
+        for matrix_name, properties in self.matrixes_configuration.items():
186
+            self.matrixes.initialize_empty_matrix(
187
+                matrix_name,
188
+                matrix_width=self.tmx_map.width,
189
+                matrix_height=self.tmx_map.height,
190
+                value_structure=properties,
191
+            )
192
+            fill_matrix(self.tmx_map, self.matrixes, 'terrain', matrix_name, properties)

+ 4 - 2
synergine2_xyz/tmx_utils.py View File

6
 
6
 
7
 from synergine2.exceptions import ConfigurationError
7
 from synergine2.exceptions import ConfigurationError
8
 from synergine2_xyz.map import TMXMap
8
 from synergine2_xyz.map import TMXMap
9
-from synergine2_xyz.physics import Matrixes
9
+
10
+if typing.TYPE_CHECKING:
11
+    from synergine2_xyz.physics import Matrixes
10
 
12
 
11
 
13
 
12
 def get_layer_by_name(map_: TileMap, layer_name: str) -> Layer:
14
 def get_layer_by_name(map_: TileMap, layer_name: str) -> Layer:
19
 
21
 
20
 def fill_matrix(
22
 def fill_matrix(
21
     tmx_map: TMXMap,
23
     tmx_map: TMXMap,
22
-    matrixes: Matrixes,
24
+    matrixes: 'Matrixes',
23
     layer_name: str,
25
     layer_name: str,
24
     matrix_name: str,
26
     matrix_name: str,
25
     properties: typing.List[str],
27
     properties: typing.List[str],

+ 10 - 0
tests/test_physics.py View File

45
         path_values = visibility.get_values_for_path('testing', path_positions=path_positions)
45
         path_values = visibility.get_values_for_path('testing', path_positions=path_positions)
46
         assert [(0.7,), (0.0,), (0.5,)] == path_values
46
         assert [(0.7,), (0.0,), (0.5,)] == path_values
47
 
47
 
48
+    def test_get_path_value(self):
49
+        visibility = Matrixes()
50
+        visibility.initialize_empty_matrix('testing', matrix_width=3, matrix_height=2, value_structure=['opacity'])
51
+        visibility.update_matrix('testing', x=2, y=1, value=(0.5,))
52
+        visibility.update_matrix('testing', x=0, y=0, value=(0.7,))
53
+
54
+        path_positions = visibility.get_path_positions(from_=(0, 0), to=(2, 1))
55
+        path_values = visibility.get_values_for_path('testing', path_positions=path_positions, value_name='opacity')
56
+        assert [0.7, 0.0, 0.5] == path_values
57
+
48
     def test_get_value(self):
58
     def test_get_value(self):
49
         visibility = Matrixes()
59
         visibility = Matrixes()
50
         visibility.initialize_empty_matrix('testing', matrix_width=3, matrix_height=2, value_structure=['opacity'])
60
         visibility.initialize_empty_matrix('testing', matrix_width=3, matrix_height=2, value_structure=['opacity'])