Browse Source

Fire cursor drawing

Bastien Sevajol 6 years ago
parent
commit
7d14642de4

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

@@ -3,6 +3,7 @@
3 3
 from pyglet.window import key
4 4
 
5 5
 from cocos.actions import MoveTo as BaseMoveTo
6
+from sandbox.tile.simulation.physics import TilePhysics
6 7
 from sandbox.tile.user_action import UserAction
7 8
 from synergine2.config import Config
8 9
 from synergine2.log import SynergineLogger
@@ -17,10 +18,19 @@ from synergine2_cocos2d.gui import TMXGui
17 18
 from synergine2_cocos2d.layer import LayerManager
18 19
 from synergine2_xyz.move.simulation import FinishMoveEvent
19 20
 from synergine2_xyz.move.simulation import StartMoveEvent
21
+from synergine2_xyz.physics import Matrixes
20 22
 from synergine2_xyz.utils import get_angle
21 23
 
22 24
 
23 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 34
     def _on_key_press(self, k, m):
25 35
         if self.selection:
26 36
             if k == key.M:
@@ -29,6 +39,8 @@ class EditLayer(BaseEditLayer):
29 39
                 self.user_action_pending = UserAction.ORDER_MOVE_FAST
30 40
             if k == key.C:
31 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 46
 class TileLayerManager(LayerManager):
@@ -78,6 +90,7 @@ class Game(TMXGui):
78 90
         self.layer_manager.interaction_manager.register(MoveActorInteraction, self.layer_manager)
79 91
         self.layer_manager.interaction_manager.register(MoveFastActorInteraction, self.layer_manager)
80 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 95
     def set_subject_position(self, event: FinishMoveEvent):
83 96
         actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]

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

@@ -0,0 +1,67 @@
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,6 +6,8 @@
6 6
    <property name="name" type="str" value="Grass"/>
7 7
    <property name="traversable_by_man" type="bool" value="true"/>
8 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 11
   </properties>
10 12
  </tile>
11 13
  <tile id="1">
@@ -13,6 +15,8 @@
13 15
    <property name="name" type="str" value="Wood wall"/>
14 16
    <property name="traversable_by_man" type="bool" value="false"/>
15 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 20
   </properties>
17 21
  </tile>
18 22
 </tileset>

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

@@ -1,27 +1,11 @@
1 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 4
 from synergine2.config import Config
7
-from synergine2_xyz.map import TMXMap
8 5
 from synergine2_xyz.physics import Physics
9
-from synergine2_xyz.physics import TMXPhysics
10 6
 from synergine2_xyz.simulation import XYZSimulation
11
-from synergine2_xyz.subjects import XYZSubjects
12 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 11
 class TileStrategySimulation(XYZSimulation):

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

@@ -0,0 +1,39 @@
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,15 +1,17 @@
1 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 7
 from synergine2_xyz.physics import MoveCostComputer
8
+from synergine2_xyz.physics import TMXPhysics
9
+from synergine2_xyz.subjects import XYZSubject
4 10
 
5 11
 if False:
6 12
     from sandbox.tile.simulation.base import BaseSubject
7 13
 
8 14
 
9
-class TerrainTile(XYZTile):
10
-    pass
11
-
12
-
13 15
 class TileMoveCostComputer(MoveCostComputer):
14 16
     def compute_move_cost(
15 17
         self,
@@ -26,3 +28,48 @@ class TileMoveCostComputer(MoveCostComputer):
26 28
             return 100
27 29
 
28 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

@@ -0,0 +1,16 @@
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,3 +6,4 @@ class UserAction(BaseUserAction):
6 6
     ORDER_MOVE = 'ORDER_MOVE'
7 7
     ORDER_MOVE_FAST = 'ORDER_MOVE_FAST'
8 8
     ORDER_MOVE_CRAWL = 'ORDER_MOVE_CRAWL'
9
+    ORDER_FIRE = 'ORDER_FIRE'

+ 7 - 3
synergine2_cocos2d/middleware.py View File

@@ -18,11 +18,15 @@ class MapMiddleware(object):
18 18
         self.map_dir_path = map_dir_path
19 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 23
             self.map_dir_path,
24 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 31
     def get_background_sprite(self) -> cocos.sprite.Sprite:
28 32
         raise NotImplementedError()

+ 33 - 5
synergine2_xyz/physics.py View File

@@ -8,6 +8,7 @@ from synergine2.config import Config
8 8
 from synergine2.share import shared
9 9
 from synergine2_xyz.map import TMXMap, XYZTile
10 10
 from synergine2_xyz.subjects import XYZSubject
11
+from synergine2_xyz.tmx_utils import fill_matrix
11 12
 from synergine2_xyz.utils import get_line_xy_path
12 13
 from synergine2_xyz.xyz import get_neighbor_positions
13 14
 
@@ -38,9 +39,7 @@ class MoveCostComputer(object):
38 39
 
39 40
 class Matrixes(object):
40 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 44
     def initialize_empty_matrix(
46 45
         self,
@@ -75,12 +74,25 @@ class Matrixes(object):
75 74
     ) -> typing.List[typing.Tuple[int, int]]:
76 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 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 89
         matrix = self.get_matrix(name)
81 90
         for path_position in path_positions:
82 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 96
         return values
85 97
 
86 98
     def get_value(self, matrix_name: str, x: int, y: int, value_name: str) -> float:
@@ -129,6 +141,7 @@ class Physics(object):
129 141
 
130 142
 class TMXPhysics(Physics):
131 143
     tmx_map_class = TMXMap
144
+    matrixes_configuration = None  # type: typing.Dict[str, typing.List[str]]
132 145
 
133 146
     def __init__(
134 147
         self,
@@ -138,9 +151,11 @@ class TMXPhysics(Physics):
138 151
         super().__init__(config)
139 152
         self.map_file_path = map_file_path
140 153
         self.tmx_map = self.tmx_map_class(map_file_path)
154
+        self.matrixes = Matrixes()
141 155
 
142 156
     def load(self) -> None:
143 157
         self.load_graph_from_map(self.map_file_path)
158
+        self.load_matrixes_from_map()
144 159
 
145 160
     def load_graph_from_map(self, map_file_path: str) -> None:
146 161
         # TODO: tmx_map contient tout en cache, faire le dessous en exploitant tmx_map.
@@ -162,3 +177,16 @@ class TMXPhysics(Physics):
162 177
                     to_tile = self.tmx_map.layer_tiles('terrain')[neighbor]
163 178
                     # Note: Voir https://pypi.python.org/pypi/Dijkstar/2.2
164 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,7 +6,9 @@ from tmx import Layer
6 6
 
7 7
 from synergine2.exceptions import ConfigurationError
8 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 14
 def get_layer_by_name(map_: TileMap, layer_name: str) -> Layer:
@@ -19,7 +21,7 @@ def get_layer_by_name(map_: TileMap, layer_name: str) -> Layer:
19 21
 
20 22
 def fill_matrix(
21 23
     tmx_map: TMXMap,
22
-    matrixes: Matrixes,
24
+    matrixes: 'Matrixes',
23 25
     layer_name: str,
24 26
     matrix_name: str,
25 27
     properties: typing.List[str],

+ 10 - 0
tests/test_physics.py View File

@@ -45,6 +45,16 @@ class TestVisibilityMatrix(BaseTest):
45 45
         path_values = visibility.get_values_for_path('testing', path_positions=path_positions)
46 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 58
     def test_get_value(self):
49 59
         visibility = Matrixes()
50 60
         visibility.initialize_empty_matrix('testing', matrix_width=3, matrix_height=2, value_structure=['opacity'])