Browse Source

move sync with interface

Bastien Sevajol 7 years ago
parent
commit
f70b523ab3

+ 2 - 0
requirements.txt View File

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

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

@@ -1,5 +1,9 @@
1 1
 core:
2
-    cycle_duration: 0.125
2
+    cycle_duration: 0.25
3 3
     use_x_cores: 1
4 4
 terminals:
5 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,9 +17,6 @@ class Man(Actor):
17 17
             'actors/man_w5.png',
18 18
             'actors/man_w6.png',
19 19
             'actors/man_w7.png',
20
-            'actors/man_w8.png',
21
-            'actors/man_w9.png',
22
-            'actors/man_w10.png',
23 20
         ],
24 21
         # ANIMATION_CRAWL: [
25 22
         #     'actors/man_c1.png',

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

@@ -2,12 +2,14 @@
2 2
 from sandbox.tile.simulation.subject import Man as ManSubject
3 3
 from sandbox.tile.gui.actor import Man as ManActor
4 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 9
 class CocosTerminal(GameTerminal):
9 10
     subscribed_events = [
10
-        MoveEvent,
11
+        FinishMoveEvent,
12
+        StartMoveEvent,
11 13
     ]
12 14
 
13 15
     def __init__(self, *args, asynchronous: bool, map_dir_path: str, **kwargs):

+ 20 - 6
synergine2_cocos2d/gui.py View File

@@ -28,7 +28,8 @@ from synergine2_cocos2d.layer import LayerManager
28 28
 from synergine2_cocos2d.middleware import MapMiddleware
29 29
 from synergine2_cocos2d.middleware import TMXMiddleware
30 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 33
 from synergine2_xyz.utils import get_angle
33 34
 from synergine2_xyz.xyz import XYZSubjectMixin
34 35
 
@@ -745,10 +746,18 @@ class TMXGui(Gui):
745 746
         )
746 747
 
747 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 761
     def get_layer_middleware(self) -> MapMiddleware:
753 762
         return TMXMiddleware(
754 763
             self.config,
@@ -769,12 +778,17 @@ class TMXGui(Gui):
769 778
         subject_mapper = self.subject_mapper_factory.get_subject_mapper(subject)
770 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 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 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 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 794
         actor.rotation = get_angle(event.from_position, event.to_position)

+ 1 - 1
synergine2_cocos2d/interaction.py View File

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

+ 74 - 11
synergine2_xyz/move.py View File

@@ -1,8 +1,11 @@
1 1
 # coding: utf-8
2 2
 import typing
3
+from random import randint
4
+
5
+import time
3 6
 
4 7
 from synergine2.config import Config
5
-from synergine2.simulation import SimulationBehaviour
8
+from synergine2.simulation import SimulationBehaviour, Subject
6 9
 from synergine2.simulation import SubjectBehaviour
7 10
 from synergine2.simulation import SubjectMechanism
8 11
 from synergine2.simulation import Intention
@@ -12,10 +15,17 @@ from synergine2_xyz.simulation import XYZSimulation
12 15
 
13 16
 
14 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 23
         self.move_to = move_to
17 24
         self.path = []  # type: typing.List[typing.Tuple[int, int]]
18 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 31
 class RequestMoveBehaviour(SimulationBehaviour):
@@ -44,7 +54,7 @@ class RequestMoveBehaviour(SimulationBehaviour):
44 54
 
45 55
         try:
46 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 58
         except KeyError:
49 59
             # TODO: log error here
50 60
             pass
@@ -89,6 +99,9 @@ class MoveToMechanism(SubjectMechanism):
89 99
 
90 100
             return {
91 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 107
         except IndexError:  # TODO: Specialize ? No movement left
@@ -97,7 +110,30 @@ class MoveToMechanism(SubjectMechanism):
97 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 137
     def __init__(
102 138
         self,
103 139
         subject_id: int,
@@ -124,12 +160,30 @@ class MoveToBehaviour(SubjectBehaviour):
124 160
     use = [MoveToMechanism]
125 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 172
     def run(self, data):
128 173
         # TODO: on fait vraiment rien ici ? Note: meme si il n'y a pas de new_path, l'action doit s'effectuer
129 174
         # du moment qu'il y a une intention de move
130 175
         move_to_data = data[self.move_to_mechanism]
131 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 185
             return move_to_data
186
+
133 187
         return False
134 188
 
135 189
     def action(self, data) -> [Event]:
@@ -144,16 +198,25 @@ class MoveToBehaviour(SubjectBehaviour):
144 198
                 move.path = new_path
145 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 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 217
             self.subject.intentions.set(move)
155 218
 
156
-            return [MoveEvent(self.subject.id, previous_position, new_position)]
219
+            return [event]
157 220
 
158 221
         except KeyError:
159 222
             # TODO: log ? Il devrait y avoir un move puisque data du run/mechanism !

+ 137 - 0
tests/test_move.py View File

@@ -0,0 +1,137 @@
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)