@@ -4,7 +4,7 @@ const GetValue = Phaser.Utils.Objects.GetValue;
44const DistanceBetween = Phaser . Math . Distance . Between ;
55const Lerp = Phaser . Math . Linear ;
66const AngleBetween = Phaser . Math . Angle . Between ;
7-
7+ const arriveEpsilon = 0.0001 ;
88
99class MoveTo extends TickTask {
1010 constructor ( gameObject , config ) {
@@ -16,34 +16,51 @@ class MoveTo extends TickTask {
1616 }
1717
1818 resetFromJSON ( o ) {
19+ this . isCompleted = GetValue ( o , 'isCompleted' , true ) ;
1920 this . isRunning = GetValue ( o , 'isRunning' , false ) ;
2021 this . setEnable ( GetValue ( o , 'enable' , true ) ) ;
2122 this . timeScale = GetValue ( o , 'timeScale' , 1 ) ;
2223 this . setSpeed ( GetValue ( o , 'speed' , 400 ) ) ;
2324 this . setRotateToTarget ( GetValue ( o , 'rotateToTarget' , false ) ) ;
24- this . targetX = GetValue ( o , 'targetX' , 0 ) ;
25- this . targetY = GetValue ( o , 'targetY' , 0 ) ;
25+ this . targetX = GetValue ( o , 'targetX' , null ) ; // Invalid
26+ this . targetY = GetValue ( o , 'targetY' , null ) ;
27+ this . appendMode = GetValue ( o , 'appendMode' , false ) ;
28+ this . targets = GetValue ( o , 'targets' , [ ] ) ; // {x,y}[]
29+
2630 return this ;
2731 }
2832
2933 toJSON ( ) {
3034 return {
35+ isCompleted : this . isCompleted ,
3136 isRunning : this . isRunning ,
3237 enable : this . enable ,
3338 timeScale : this . timeScale ,
3439 speed : this . speed ,
3540 rotateToTarget : this . rotateToTarget ,
3641 targetX : this . targetX ,
3742 targetY : this . targetY ,
38- tickingMode : this . tickingMode
43+ tickingMode : this . tickingMode ,
44+ appendMode : this . appendMode ,
45+ targets : this . targets
3946 } ;
4047 }
4148
42- setEnable ( e ) {
43- if ( e == undefined ) {
44- e = true ;
49+ get lastTargetPosition ( ) {
50+ var queuedLength = this . targets . length ;
51+ if ( queuedLength === 0 ) {
52+ return { x : this . targetX , y : this . targetY } ;
53+ } else {
54+ var lastTarget = this . targets [ queuedLength - 1 ] ;
55+ return { x : lastTarget . x , y : lastTarget . y } ;
4556 }
46- this . enable = e ;
57+ }
58+
59+ setEnable ( enable ) {
60+ if ( enable == undefined ) {
61+ enable = true ;
62+ }
63+ this . enable = enable ;
4764 return this ;
4865 }
4966
@@ -57,27 +74,75 @@ class MoveTo extends TickTask {
5774 return this ;
5875 }
5976
77+ setAppendMode ( appendMode ) {
78+ this . appendMode = ! ! appendMode ;
79+
80+ if ( ! this . appendMode ) {
81+ this . clearTargets ( ) ;
82+ }
83+ return this ;
84+ }
85+
86+ clearTargets ( ) {
87+ this . targets . length = 0 ;
88+ return this ;
89+ }
90+
6091 moveTo ( x , y ) {
92+ if ( x === undefined ) {
93+ if ( ! this . isCompleted ) { // Resume
94+ super . start ( ) ;
95+ } else {
96+ // Does not have target position, do nothing
97+ }
98+ return this ;
99+ }
100+
61101 if ( typeof ( x ) !== 'number' ) {
62102 var config = x ;
63103 x = config . x ;
64104 y = config . y ;
65105 }
66106
67- this . targetX = x ;
68- this . targetY = y ;
69- super . start ( ) ;
70- this . emit ( 'start' , this . parent , this ) ;
107+ var isNewTask = false ;
108+ if ( this . appendMode ) {
109+ if ( this . isCompleted ) { // New task
110+ this . targetX = x ;
111+ this . targetY = y ;
112+ isNewTask = true ;
113+
114+ } else {
115+ this . targets . push ( { x, y } ) ;
116+
117+ }
118+
119+ } else {
120+
121+ this . targetX = x ;
122+ this . targetY = y ;
123+ isNewTask = true ;
124+
125+ }
126+
127+ if ( isNewTask ) {
128+ super . start ( ) ;
129+ this . emit ( 'start' , this . parent , this ) ;
130+ }
131+
71132 return this ;
72133 }
73134
74135 moveFrom ( x , y ) {
136+ // This method will clear queue targets
137+
75138 if ( typeof ( x ) !== 'number' ) {
76139 var config = x ;
77140 x = config . x ;
78141 y = config . y ;
79142 }
80143
144+ this . stop ( ) ;
145+
81146 var gameObject = this . parent ;
82147 var targetX = gameObject . x ;
83148 var targetY = gameObject . y ;
@@ -90,10 +155,38 @@ class MoveTo extends TickTask {
90155 }
91156
92157 moveToward ( angle , distance ) {
93- var gameObject = this . parent ;
94- var targetX = gameObject . x + Math . cos ( angle ) * distance ;
95- var targetY = gameObject . y + Math . sin ( angle ) * distance ;
158+ var referencePosition ;
159+
160+ if ( this . appendMode && ! this . isCompleted ) {
161+ referencePosition = this . lastTargetPosition ;
162+
163+ } else {
164+ referencePosition = this . parent ; // gameObject
165+ }
166+
167+ var targetX = referencePosition . x + Math . cos ( angle ) * distance ;
168+ var targetY = referencePosition . y + Math . sin ( angle ) * distance ;
96169 this . moveTo ( targetX , targetY ) ;
170+
171+ return this ;
172+ }
173+
174+ start ( ) {
175+ this . isCompleted = false ;
176+ super . start ( ) ;
177+ return this ;
178+ }
179+
180+ stop ( ) {
181+ super . stop ( ) ;
182+ this . clearTargets ( ) ;
183+ this . isCompleted = true ;
184+ return this ;
185+ }
186+
187+ complete ( ) {
188+ super . complete ( ) ;
189+ this . isCompleted = true ;
97190 return this ;
98191 }
99192
@@ -102,41 +195,83 @@ class MoveTo extends TickTask {
102195 return this ;
103196 }
104197
105- var gameObject = this . parent ;
106- if ( ! gameObject . active ) {
198+ if ( this . targetX == null || this . targetY == null ) {
199+ this . stop ( ) ;
107200 return this ;
108201 }
109202
110- var curX = gameObject . x ,
111- curY = gameObject . y ;
112- var targetX = this . targetX ,
113- targetY = this . targetY ;
114- if ( ( curX === targetX ) && ( curY === targetY ) ) {
115- this . complete ( ) ;
203+ var gameObject = this . parent ;
204+ if ( ! gameObject . active ) {
116205 return this ;
117206 }
118207
119208 if ( ( this . speed === 0 ) || ( delta === 0 ) || ( this . timeScale === 0 ) ) {
120209 return this ;
121210 }
122211
123- var dt = ( delta * this . timeScale ) / 1000 ;
124- var movingDist = this . speed * dt ;
125- var distToTarget = DistanceBetween ( curX , curY , targetX , targetY ) ;
126- var newX , newY ;
127- if ( movingDist < distToTarget ) {
128- var t = movingDist / distToTarget ;
129- newX = Lerp ( curX , targetX , t ) ;
130- newY = Lerp ( curY , targetY , t ) ;
131- } else {
132- newX = targetX ;
133- newY = targetY ;
134- }
212+ var deltaSeconds = ( delta * this . timeScale ) / 1000 ;
213+ var remainingDistanceBudget = this . speed * deltaSeconds ;
214+
215+ // Consume remainingDistanceBudget across multiple targets in the same tick
216+ while ( remainingDistanceBudget > 0 ) {
217+ var currentX = gameObject . x ;
218+ var currentY = gameObject . y ;
219+
220+ var targetX = this . targetX ;
221+ var targetY = this . targetY ;
222+
223+ var distanceToTarget = DistanceBetween ( currentX , currentY , targetX , targetY ) ;
224+
225+ // If already on the current target, switch to next target or complete
226+ if ( distanceToTarget <= arriveEpsilon ) {
227+ if ( this . targets . length > 0 ) {
228+ var nextTarget = this . targets . shift ( ) ;
229+ this . targetX = nextTarget . x ;
230+ this . targetY = nextTarget . y ;
231+ continue ;
232+ }
233+
234+ this . complete ( ) ;
235+ return this ;
236+ }
237+
238+ // Move partially toward target
239+ else if ( remainingDistanceBudget < distanceToTarget ) {
240+ var t = remainingDistanceBudget / distanceToTarget ;
241+ var newX = Lerp ( currentX , targetX , t ) ;
242+ var newY = Lerp ( currentY , targetY , t ) ;
243+
244+ gameObject . setPosition ( newX , newY ) ;
245+
246+ if ( this . rotateToTarget ) {
247+ gameObject . rotation = AngleBetween ( currentX , currentY , newX , newY ) ;
248+ }
135249
136- gameObject . setPosition ( newX , newY ) ;
137- if ( this . rotateToTarget ) {
138- gameObject . rotation = AngleBetween ( curX , curY , newX , newY ) ;
250+ remainingDistanceBudget = 0 ;
251+ break ;
252+ }
253+
254+ // Reach target and still have remaining distance budget
255+ gameObject . setPosition ( targetX , targetY ) ;
256+
257+ if ( this . rotateToTarget ) {
258+ gameObject . rotation = AngleBetween ( currentX , currentY , targetX , targetY ) ;
259+ }
260+
261+ remainingDistanceBudget -= distanceToTarget ;
262+
263+ // Continue to next target if any, otherwise complete
264+ if ( this . targets . length > 0 ) {
265+ var nextTargetAfterReach = this . targets . shift ( ) ;
266+ this . targetX = nextTargetAfterReach . x ;
267+ this . targetY = nextTargetAfterReach . y ;
268+ continue ;
269+ }
270+
271+ this . complete ( ) ;
272+ return this ;
139273 }
274+
140275 return this ;
141276 }
142277}
0 commit comments