Browse Source

move sync with interface

Bastien Sevajol 7 years ago
parent
commit
f70b523ab3

+ 2 - 0
requirements.txt View File

4
 coverage==4.4.1
4
 coverage==4.4.1
5
 Dijkstar==2.2
5
 Dijkstar==2.2
6
 execnet==1.4.1
6
 execnet==1.4.1
7
+freezegun==0.3.9
7
 numpy==1.13.1
8
 numpy==1.13.1
8
 packaging==16.8
9
 packaging==16.8
9
 psutil==5.2.2
10
 psutil==5.2.2
14
 pytest-cov==2.5.1
15
 pytest-cov==2.5.1
15
 pytest-timeout==1.2.0
16
 pytest-timeout==1.2.0
16
 pytest-xdist==1.16.0
17
 pytest-xdist==1.16.0
18
+python-dateutil==2.6.1
17
 PyYAML==3.12
19
 PyYAML==3.12
18
 redis==2.10.6
20
 redis==2.10.6
19
 six==1.10.0
21
 six==1.10.0

+ 5 - 1
sandbox/tile/config.yaml View File

1
 core:
1
 core:
2
-    cycle_duration: 0.125
2
+    cycle_duration: 0.25
3
     use_x_cores: 1
3
     use_x_cores: 1
4
 terminals:
4
 terminals:
5
     sync: True
5
     sync: True
6
+game:
7
+    move:
8
+        walk_ref_time: 3
9
+        run_ref_time: 1.5

+ 0 - 3
sandbox/tile/gui/actor.py View File

17
             'actors/man_w5.png',
17
             'actors/man_w5.png',
18
             'actors/man_w6.png',
18
             'actors/man_w6.png',
19
             'actors/man_w7.png',
19
             'actors/man_w7.png',
20
-            'actors/man_w8.png',
21
-            'actors/man_w9.png',
22
-            'actors/man_w10.png',
23
         ],
20
         ],
24
         # ANIMATION_CRAWL: [
21
         # ANIMATION_CRAWL: [
25
         #     'actors/man_c1.png',
22
         #     'actors/man_c1.png',

+ 4 - 2
sandbox/tile/terminal/base.py View File

2
 from sandbox.tile.simulation.subject import Man as ManSubject
2
 from sandbox.tile.simulation.subject import Man as ManSubject
3
 from sandbox.tile.gui.actor import Man as ManActor
3
 from sandbox.tile.gui.actor import Man as ManActor
4
 from synergine2_cocos2d.terminal import GameTerminal
4
 from synergine2_cocos2d.terminal import GameTerminal
5
-from synergine2_xyz.move import MoveEvent
5
+from synergine2_xyz.move import FinishMoveEvent
6
+from synergine2_xyz.move import StartMoveEvent
6
 
7
 
7
 
8
 
8
 class CocosTerminal(GameTerminal):
9
 class CocosTerminal(GameTerminal):
9
     subscribed_events = [
10
     subscribed_events = [
10
-        MoveEvent,
11
+        FinishMoveEvent,
12
+        StartMoveEvent,
11
     ]
13
     ]
12
 
14
 
13
     def __init__(self, *args, asynchronous: bool, map_dir_path: str, **kwargs):
15
     def __init__(self, *args, asynchronous: bool, map_dir_path: str, **kwargs):

+ 20 - 6
synergine2_cocos2d/gui.py View File

28
 from synergine2_cocos2d.middleware import MapMiddleware
28
 from synergine2_cocos2d.middleware import MapMiddleware
29
 from synergine2_cocos2d.middleware import TMXMiddleware
29
 from synergine2_cocos2d.middleware import TMXMiddleware
30
 from synergine2_cocos2d.user_action import UserAction
30
 from synergine2_cocos2d.user_action import UserAction
31
-from synergine2_xyz.move import MoveEvent
31
+from synergine2_xyz.move import FinishMoveEvent
32
+from synergine2_xyz.move import StartMoveEvent
32
 from synergine2_xyz.utils import get_angle
33
 from synergine2_xyz.utils import get_angle
33
 from synergine2_xyz.xyz import XYZSubjectMixin
34
 from synergine2_xyz.xyz import XYZSubjectMixin
34
 
35
 
745
         )
746
         )
746
 
747
 
747
         self.terminal.register_event_handler(
748
         self.terminal.register_event_handler(
748
-            MoveEvent,
749
-            self.move_subject,
749
+            FinishMoveEvent,
750
+            self.set_subject_position,
750
         )
751
         )
751
 
752
 
753
+        self.terminal.register_event_handler(
754
+            StartMoveEvent,
755
+            self.start_move_subject,
756
+        )
757
+
758
+        # configs
759
+        self.move_duration_ref = float(self.config.resolve('game.move.walk_ref_time'))
760
+
752
     def get_layer_middleware(self) -> MapMiddleware:
761
     def get_layer_middleware(self) -> MapMiddleware:
753
         return TMXMiddleware(
762
         return TMXMiddleware(
754
             self.config,
763
             self.config,
769
         subject_mapper = self.subject_mapper_factory.get_subject_mapper(subject)
778
         subject_mapper = self.subject_mapper_factory.get_subject_mapper(subject)
770
         subject_mapper.append(subject, self.layer_manager)
779
         subject_mapper.append(subject, self.layer_manager)
771
 
780
 
772
-    def move_subject(self, event: MoveEvent):
781
+    def set_subject_position(self, event: FinishMoveEvent):
773
         actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]
782
         actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]
783
+        new_world_position = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(event.to_position)
784
+
785
+        actor.set_position(*new_world_position)
774
 
786
 
787
+    def start_move_subject(self, event: StartMoveEvent):
788
+        actor = self.layer_manager.subject_layer.subjects_index[event.subject_id]
775
         new_world_position = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(event.to_position)
789
         new_world_position = self.layer_manager.grid_manager.get_pixel_position_of_grid_position(event.to_position)
776
 
790
 
777
-        move_action = MoveTo(new_world_position, 0.5)
791
+        move_action = MoveTo(new_world_position, self.move_duration_ref)
778
         actor.do(move_action)
792
         actor.do(move_action)
779
-        actor.do(Animate(ANIMATION_WALK, 0.5, 1))
793
+        actor.do(Animate(ANIMATION_WALK, duration=self.move_duration_ref, cycle_duration=2))
780
         actor.rotation = get_angle(event.from_position, event.to_position)
794
         actor.rotation = get_angle(event.from_position, event.to_position)

+ 1 - 1
synergine2_cocos2d/interaction.py View File

86
                 )
86
                 )
87
 
87
 
88
     def get_package_for_terminal(self) -> TerminalPackage:
88
     def get_package_for_terminal(self) -> TerminalPackage:
89
-        # TODO: MoveEvent ?
89
+        # TODO: FinishMoveEvent ?
90
         actions = []
90
         actions = []
91
         mouse_grid_position = self.layer_manager.grid_manager.get_grid_position(
91
         mouse_grid_position = self.layer_manager.grid_manager.get_grid_position(
92
             self.layer_manager.scrolling_manager.screen_to_world(
92
             self.layer_manager.scrolling_manager.screen_to_world(

+ 74 - 11
synergine2_xyz/move.py View File

1
 # coding: utf-8
1
 # coding: utf-8
2
 import typing
2
 import typing
3
+from random import randint
4
+
5
+import time
3
 
6
 
4
 from synergine2.config import Config
7
 from synergine2.config import Config
5
-from synergine2.simulation import SimulationBehaviour
8
+from synergine2.simulation import SimulationBehaviour, Subject
6
 from synergine2.simulation import SubjectBehaviour
9
 from synergine2.simulation import SubjectBehaviour
7
 from synergine2.simulation import SubjectMechanism
10
 from synergine2.simulation import SubjectMechanism
8
 from synergine2.simulation import Intention
11
 from synergine2.simulation import Intention
12
 
15
 
13
 
16
 
14
 class MoveToIntention(Intention):
17
 class MoveToIntention(Intention):
15
-    def __init__(self, move_to: typing.Tuple[int, int]) -> None:
18
+    def __init__(
19
+        self,
20
+        move_to: typing.Tuple[int, int],
21
+        start_time: float,
22
+    ) -> None:
16
         self.move_to = move_to
23
         self.move_to = move_to
17
         self.path = []  # type: typing.List[typing.Tuple[int, int]]
24
         self.path = []  # type: typing.List[typing.Tuple[int, int]]
18
         self.path_progression = -1  # type: int
25
         self.path_progression = -1  # type: int
26
+        self.last_intention_time = start_time
27
+        self.just_reach = False
28
+        self.initial = True
19
 
29
 
20
 
30
 
21
 class RequestMoveBehaviour(SimulationBehaviour):
31
 class RequestMoveBehaviour(SimulationBehaviour):
44
 
54
 
45
         try:
55
         try:
46
             subject = self.simulation.subjects.index[subject_id]
56
             subject = self.simulation.subjects.index[subject_id]
47
-            subject.intentions.set(self.move_intention_class(move_to))
57
+            subject.intentions.set(self.move_intention_class(move_to, start_time=time.time()))
48
         except KeyError:
58
         except KeyError:
49
             # TODO: log error here
59
             # TODO: log error here
50
             pass
60
             pass
89
 
99
 
90
             return {
100
             return {
91
                 'new_path': new_path,
101
                 'new_path': new_path,
102
+                'last_intention_time': move.last_intention_time,
103
+                'just_reach': move.just_reach,
104
+                'initial': move.initial,
92
             }
105
             }
93
 
106
 
94
         except IndexError:  # TODO: Specialize ? No movement left
107
         except IndexError:  # TODO: Specialize ? No movement left
97
             return None
110
             return None
98
 
111
 
99
 
112
 
100
-class MoveEvent(Event):
113
+class FinishMoveEvent(Event):
114
+    def __init__(
115
+        self,
116
+        subject_id: int,
117
+        from_position: typing.Tuple[int, int],
118
+        to_position: typing.Tuple[int, int],
119
+        *args,
120
+        **kwargs
121
+    ):
122
+        super().__init__(*args, **kwargs)
123
+        self.subject_id = subject_id
124
+        self.from_position = from_position
125
+        self.to_position = to_position
126
+
127
+    def repr_debug(self) -> str:
128
+        return '{}: subject_id:{}, from_position:{} to_position: {}'.format(
129
+            type(self).__name__,
130
+            self.subject_id,
131
+            self.from_position,
132
+            self.to_position,
133
+        )
134
+
135
+
136
+class StartMoveEvent(Event):
101
     def __init__(
137
     def __init__(
102
         self,
138
         self,
103
         subject_id: int,
139
         subject_id: int,
124
     use = [MoveToMechanism]
160
     use = [MoveToMechanism]
125
     move_to_mechanism = MoveToMechanism
161
     move_to_mechanism = MoveToMechanism
126
 
162
 
163
+    def __init__(
164
+        self,
165
+        config: Config,
166
+        simulation: Simulation,
167
+        subject: Subject,
168
+    ) -> None:
169
+        super().__init__(config, simulation, subject)
170
+        self._duration = float(self.config.resolve('game.move.walk_ref_time'))
171
+
127
     def run(self, data):
172
     def run(self, data):
128
         # TODO: on fait vraiment rien ici ? Note: meme si il n'y a pas de new_path, l'action doit s'effectuer
173
         # TODO: on fait vraiment rien ici ? Note: meme si il n'y a pas de new_path, l'action doit s'effectuer
129
         # du moment qu'il y a une intention de move
174
         # du moment qu'il y a une intention de move
130
         move_to_data = data[self.move_to_mechanism]
175
         move_to_data = data[self.move_to_mechanism]
131
         if move_to_data:
176
         if move_to_data:
177
+
178
+            if time.time() - move_to_data['last_intention_time'] >= self._duration:
179
+                move_to_data['reach_next'] = True
180
+            elif move_to_data['just_reach'] or move_to_data['initial']:
181
+                move_to_data['reach_next'] = False
182
+            else:
183
+                return False
184
+
132
             return move_to_data
185
             return move_to_data
186
+
133
         return False
187
         return False
134
 
188
 
135
     def action(self, data) -> [Event]:
189
     def action(self, data) -> [Event]:
144
                 move.path = new_path
198
                 move.path = new_path
145
                 move.path_progression = -1
199
                 move.path_progression = -1
146
 
200
 
147
-            # TODO: progression et lorsque "vraiment avance d'une case" envoyer le Move
148
-            # pour le moment on move direct
149
-            # TODO: fin de path
150
-            move.path_progression += 1
151
-            new_position = move.path[move.path_progression]
152
             previous_position = self.subject.position
201
             previous_position = self.subject.position
153
-            self.subject.position = new_position
202
+            new_position = move.path[move.path_progression + 1]
203
+
204
+            if data['reach_next']:
205
+                # TODO: fin de path
206
+                move.path_progression += 1
207
+                self.subject.position = new_position
208
+                move.last_intention_time = time.time()
209
+                move.just_reach = True
210
+                event = FinishMoveEvent(self.subject.id, previous_position, new_position)
211
+            else:
212
+                move.just_reach = False
213
+                event = StartMoveEvent(self.subject.id, previous_position, new_position)
214
+
215
+            move.initial = False
216
+            # Note: Need to explicitly set to update shared data
154
             self.subject.intentions.set(move)
217
             self.subject.intentions.set(move)
155
 
218
 
156
-            return [MoveEvent(self.subject.id, previous_position, new_position)]
219
+            return [event]
157
 
220
 
158
         except KeyError:
221
         except KeyError:
159
             # TODO: log ? Il devrait y avoir un move puisque data du run/mechanism !
222
             # TODO: log ? Il devrait y avoir un move puisque data du run/mechanism !

+ 137 - 0
tests/test_move.py View File

1
+# coding: utf-8
2
+import time
3
+
4
+from freezegun import freeze_time
5
+
6
+from synergine2.config import Config
7
+from synergine2_xyz.move import MoveToBehaviour, MoveToMechanism, MoveToIntention, StartMoveEvent, FinishMoveEvent
8
+from synergine2_xyz.simulation import XYZSimulation
9
+from synergine2_xyz.subjects import XYZSubject
10
+from tests import BaseTest
11
+
12
+
13
+class MySubject(XYZSubject):
14
+    pass
15
+
16
+
17
+class MySimulation(XYZSimulation):
18
+    pass
19
+
20
+
21
+class TestMove(BaseTest):
22
+    def test_behaviour_cycle(self):
23
+        config = Config({
24
+            'game': {
25
+                'move': {
26
+                    'walk_ref_time': 2,
27
+                }
28
+            }
29
+        })
30
+        simulation = MySimulation(config)
31
+        subject = MySubject(config, simulation)
32
+        behaviour = MoveToBehaviour(config, simulation, subject)
33
+
34
+        with freeze_time("2000-01-01 00:00:00"):
35
+            move_intention = MoveToIntention((0, 3), time.time())
36
+
37
+            assert move_intention.path_progression == -1
38
+            assert move_intention.just_reach is False
39
+            assert move_intention.initial is True
40
+
41
+            subject.intentions.set(move_intention)
42
+            move_data = {
43
+                'new_path': [(0, 1), (0, 2)],
44
+                'last_intention_time': time.time(),
45
+                'just_reach': False,
46
+                'initial': True,
47
+            }
48
+            data = {
49
+                MoveToMechanism: move_data,
50
+            }
51
+            run_data = behaviour.run(data)
52
+
53
+            assert move_data == run_data
54
+            events = behaviour.action(run_data)
55
+
56
+        assert events
57
+        assert 1 == len(events)
58
+        assert isinstance(events[0], StartMoveEvent)
59
+
60
+        assert move_intention.path_progression == -1
61
+        assert move_intention.just_reach is False
62
+        assert move_intention.initial is False
63
+
64
+        # Update data like mechanism do it
65
+        move_data['last_intention_time'] = move_intention.last_intention_time
66
+        move_data['just_reach'] = move_intention.just_reach
67
+        move_data['initial'] = move_intention.initial
68
+
69
+        # Only one second, no reach
70
+        with freeze_time("2000-01-01 00:00:01"):
71
+            run_data = behaviour.run(data)
72
+
73
+        assert run_data is False
74
+
75
+        # Two second, step reach
76
+        with freeze_time("2000-01-01 00:00:02"):
77
+            run_data = behaviour.run(data)
78
+
79
+            assert {
80
+                       'new_path': [(0, 1), (0, 2)],
81
+                       'initial': False,
82
+                       'just_reach': False,
83
+                       'last_intention_time': 946684800.0,
84
+                       'reach_next': True,
85
+                   } == run_data
86
+
87
+            events = behaviour.action(run_data)
88
+
89
+            assert events
90
+            assert 1 == len(events)
91
+            assert isinstance(events[0], FinishMoveEvent)
92
+
93
+        # Update data like mechanism do it
94
+        move_data['last_intention_time'] = move_intention.last_intention_time
95
+        move_data['just_reach'] = move_intention.just_reach
96
+        move_data['initial'] = move_intention.initial
97
+
98
+        # Three seconds, start a new move
99
+        with freeze_time("2000-01-01 00:00:03"):
100
+            run_data = behaviour.run(data)
101
+
102
+            assert {
103
+                       'new_path': [(0, 1), (0, 2)],
104
+                       'initial': False,
105
+                       'just_reach': True,
106
+                       'last_intention_time': 946684802.0,
107
+                       'reach_next': False,
108
+                   } == run_data
109
+
110
+            events = behaviour.action(run_data)
111
+
112
+            assert events
113
+            assert 1 == len(events)
114
+            assert isinstance(events[0], StartMoveEvent)
115
+
116
+        # Update data like mechanism do it
117
+        move_data['last_intention_time'] = move_intention.last_intention_time
118
+        move_data['just_reach'] = move_intention.just_reach
119
+        move_data['initial'] = move_intention.initial
120
+
121
+        # Four seconds, start a new move
122
+        with freeze_time("2000-01-01 00:00:04"):
123
+            run_data = behaviour.run(data)
124
+
125
+            assert {
126
+                       'new_path': [(0, 1), (0, 2)],
127
+                       'initial': False,
128
+                       'just_reach': False,
129
+                       'last_intention_time': 946684802.0,
130
+                       'reach_next': True,
131
+                   } == run_data
132
+
133
+            events = behaviour.action(run_data)
134
+
135
+            assert events
136
+            assert 1 == len(events)
137
+            assert isinstance(events[0], FinishMoveEvent)