Many updates, see CHANGLOG diff
[rokon:rokon.git] / src / com / stickycoding / rokon / Sprite.java
1 package com.stickycoding.rokon;\r
2 \r
3 \r
4 /**\r
5  * DynamicObject.java\r
6  * A child of StaticObject, DynamicObject has functions for time dependent movement and rotation\r
7  * \r
8  * There are two types of translational movement, one based on X and Y, and one based on a magnitude and angle\r
9  * The two methods can be used together, though it is recommended to avoid this - it may be easy to get confused\r
10  * \r
11  * @author Richard\r
12  */\r
13 \r
14 public class Sprite extends GameObject implements Updateable {\r
15 \r
16         \r
17         /**\r
18          * Constants used for rotateTo\r
19          */\r
20         public static final int ROTATE_TO_AUTOMATIC = 0, ROTATE_TO_CLOCKWISE = 1, ROTATE_TO_ANTI_CLOCKWISE = 2;\r
21 \r
22         /**\r
23          * The maximum number of Modifiers which can be active on a Sprite\r
24          */\r
25         public static final int MAX_MODIFIERS = 8;\r
26         \r
27         protected int modifierCount = 0;\r
28         protected Modifier[] modifier = new Modifier[MAX_MODIFIERS];\r
29         \r
30         protected boolean isRotateTo = false;\r
31         protected float rotateToAngleStart, rotateToAngle;\r
32         protected long rotateToStartTime;\r
33         protected int rotateToTime, rotateToType, rotateToDirection;\r
34         protected Callback rotateToCallback;\r
35         \r
36         protected Polygon polygon = Rokon.rectangle;\r
37         \r
38         /**\r
39          * Sets a Polygon for this Sprite\r
40          * \r
41          * @param polygon valid Polygon\r
42          */\r
43         public void setPolygon(Polygon polygon) {\r
44                 this.polygon = polygon;\r
45         }\r
46         \r
47         /**\r
48          * Fetches the Polygon associated with this Sprite. If none is set, it defaults to Rokon.rectangle\r
49          * \r
50          * @return Polygon object\r
51          */\r
52         public Polygon getPolygon() {\r
53                 return polygon;\r
54         }\r
55 \r
56         /**\r
57          * Returns a specific vertex of this Sprite, as it is drawn. Taking into account scaling and rotations.\r
58          * \r
59          * @param index vertex position\r
60          * \r
61          * @return float array, contains two elements, 0=X 1=Y \r
62          */\r
63         public float[] getVertex(int index) {\r
64                 if(rotation != 0) {\r
65                         float x = getX() + (getWidth() * polygon.vertex[index].getX());\r
66                         float y = getY() + (getHeight() * polygon.vertex[index].getY());\r
67                         float pivotX = getX() + (getWidth() * 0.5f);\r
68                         float pivotY = getY() + (getHeight() * 0.5f);\r
69                         float[] f = MathHelper.rotate(rotation, x, y, pivotX, pivotY);\r
70                         return f;\r
71                 } else {\r
72                         return new float[] { getX() + (getWidth() * polygon.vertex[index].getX()), getY() + (getHeight() * polygon.vertex[index].getY()) };\r
73                 }\r
74         }\r
75         \r
76         /**\r
77          * Creates a Sprite with given dimensions\r
78          * \r
79          * @param x x coordinate\r
80          * @param y y coordinate\r
81          * @param width width\r
82          * @param height height\r
83          */\r
84         public Sprite(float x, float y, float width, float height) {\r
85                 super(x, y, width, height);\r
86         }\r
87         \r
88         /**\r
89          * Called when the DynamicObject is removed from a Layer\r
90          */\r
91         public void onRemove() {\r
92                 super.onRemove();\r
93                 rotateToCallback = null;\r
94                 moveToCallback = null;\r
95         }\r
96         \r
97         /**\r
98          * Stops all the dynamics for this object\r
99          */\r
100         public void stop() {\r
101                 isMoveTo = false;\r
102                 accelerationX = 0;\r
103                 accelerationY = 0;\r
104                 acceleration = 0;\r
105                 speedX = 0;\r
106                 speedY = 0;\r
107                 velocity = 0;\r
108                 velocityXFactor = 0;\r
109                 velocityYFactor = 0;\r
110                 velocityAngle = 0;\r
111                 terminalSpeedX = 0;\r
112                 terminalSpeedY = 0;\r
113                 terminalVelocity = 0;\r
114                 angularVelocity = 0;\r
115                 angularAcceleration = 0;\r
116                 terminalAngularVelocity = 0;\r
117         }\r
118         \r
119         protected void updatePosition() {\r
120                 if(accelerationX == 0 && accelerationY == 0 && speedX == 0 && speedY == 0 && velocity == 0 && angularVelocity == 0 && angularAcceleration == 0) return;\r
121                 if(accelerationX != 0) {\r
122                         speedX += accelerationX * Time.loopTicksFraction;\r
123                         if(useTerminalSpeedX && ((accelerationX > 0 && speedX > terminalSpeedX) || (accelerationX < 0 && speedY < terminalSpeedX))) {\r
124                                 accelerationX = 0;\r
125                                 speedX = terminalSpeedX;\r
126                                 if(parentScene.useInvoke) attemptInvoke("onReachTerminalSpeedX");\r
127                         }\r
128                 }\r
129                 if(accelerationY != 0) {\r
130                         speedY += accelerationY * Time.loopTicksFraction;\r
131                         if(useTerminalSpeedY && ((accelerationY > 0 && speedY > terminalSpeedY) || (accelerationY < 0 && speedY < terminalSpeedY))) {\r
132                                 accelerationY = 0;\r
133                                 speedY = terminalSpeedY;\r
134                                 if(parentScene.useInvoke) attemptInvoke("onReachTerminalSpeedY");\r
135                         }\r
136                 }\r
137                 if(speedX != 0) {\r
138                         moveX(speedX * Time.loopTicksFraction);\r
139                 }\r
140                 if(speedY != 0) {\r
141                         moveY(speedY * Time.loopTicksFraction);\r
142                 }\r
143                 if(acceleration != 0) {\r
144                         velocity += acceleration * Time.loopTicksFraction;\r
145                         if(useTerminalVelocity && ((acceleration > 0 && velocity > terminalVelocity) || (acceleration < 0 && velocity < terminalVelocity))) {\r
146                                 acceleration = 0;\r
147                                 velocity = terminalVelocity;\r
148                                 if(parentScene.useInvoke) attemptInvoke("onReachTerminalVelocity");\r
149                         }\r
150                 }\r
151                 if(velocity != 0) {\r
152                         moveX(velocityXFactor * (velocity * Time.loopTicksFraction));\r
153                         moveY(velocityYFactor * (velocity * Time.loopTicksFraction));\r
154                 }\r
155                 if(angularAcceleration != 0) {\r
156                         angularVelocity += angularAcceleration * Time.loopTicksFraction;\r
157                         if(useTerminalAngularVelocity && ((angularAcceleration > 0 && angularVelocity > terminalAngularVelocity) || (angularAcceleration < 0 && angularVelocity < terminalAngularVelocity))) {\r
158                                 angularAcceleration = 0;\r
159                                 angularVelocity = terminalAngularVelocity;\r
160                                 attemptInvoke("onReachTerminalAngularVelocity");\r
161                         }\r
162                 }\r
163                 if(angularVelocity != 0) {\r
164                         rotation += angularVelocity * Time.loopTicksFraction;\r
165                 }\r
166         }\r
167         \r
168         public void onUpdate() {\r
169                 super.onUpdate();\r
170                 if(isMoveTo) {\r
171                         onUpdateMoveTo();\r
172                 }\r
173                 if(isRotateTo) {\r
174                         onUpdateRotateTo();\r
175                 }\r
176                 updatePosition();\r
177                 updateModifiers();\r
178         }\r
179         \r
180         protected void updateModifiers() {\r
181                 if(modifierCount > 0) {\r
182                         for(int i = 0; i < MAX_MODIFIERS; i++) {\r
183                                 if(modifier[i] != null) {\r
184                                         modifier[i].onUpdate(this);\r
185                                 }\r
186                         }\r
187                 }\r
188         }\r
189         \r
190         /**\r
191          * Sets speed of the DynamicObject in the X direction\r
192          * \r
193          * @param x positive or negative floating point\r
194          */\r
195         public void setSpeedX(float x) {\r
196                 speedX = x;\r
197         }\r
198         \r
199         /**\r
200          * Sets speed of the DynamicObject in the Y direction\r
201          * \r
202          * @param y positive or negative floating point\r
203          */\r
204         public void setSpeedY(float y) {\r
205                 speedY = y;\r
206         }\r
207         \r
208         /**\r
209          * Sets the speed of the DynamicObject on both X and Y axis\r
210          * \r
211          * @param x positive or negative floating point\r
212          * @param y positive or negative floating point\r
213          */\r
214         public void setSpeed(float x, float y) {\r
215                 speedX = x;\r
216                 speedY = y;\r
217         }\r
218         \r
219         /**\r
220          * Sets the velocity of the DynamicObject\r
221          * This is along the velocityAngle, and will be north if previously unset\r
222          * \r
223          * @param velocity positive or negative floating point\r
224          */\r
225         public void setVelocity(int velocity) {\r
226                 this.velocity = velocity;\r
227         }\r
228         \r
229         /**\r
230          * Sets the velocity of the DynamicObject\r
231          * \r
232          * @param velocity positive or negative floating point\r
233          * @param angle relative to north, in degrees\r
234          */\r
235         public void setVelocity(float velocity, float angle) {\r
236                 this.velocity = velocity;\r
237                 this.velocityAngle = angle;\r
238                 this.velocityXFactor = (float)Math.sin(angle * MathHelper.DEG_TO_RAD);\r
239                 this.velocityYFactor = (float)Math.cos(angle * MathHelper.DEG_TO_RAD);\r
240         }\r
241         \r
242         /**\r
243          * Accelerates along the X direction\r
244          * \r
245          * @param accelerationX positive or negative floating point\r
246          */\r
247         public void accelerateX(float accelerationX) {\r
248                 this.accelerationX = accelerationX;\r
249         }\r
250         \r
251         public void accelerateX(float accelerationX, float terminalSpeedX) {\r
252                 this.accelerationX = accelerationX;\r
253                 this.terminalSpeedX = terminalSpeedX;\r
254                 useTerminalSpeedX = true;\r
255         }\r
256         \r
257         /**\r
258          * Accelerates along the Y direction\r
259          * \r
260          * @param accelerationY positive or negative floating point\r
261          */\r
262         public void accelerateY(float accelerationY) {\r
263                 this.accelerationY = accelerationY;\r
264         }\r
265         \r
266         /**\r
267          * Accelerates along the Y direction to a maximum speed\r
268          *\r
269          * @param accelerationY positive or negative floating point\r
270          * @param terminalSpeedY the maximum speed to achieve in Y direction\r
271          */\r
272         public void accelerateY(float accelerationY, float terminalSpeedY) {\r
273                 this.accelerationY = accelerationY;\r
274                 this.terminalSpeedY = terminalSpeedY;\r
275                 useTerminalSpeedY = true;\r
276         }\r
277         \r
278         /**\r
279          * Accelerates along a given angle\r
280          * \r
281          * @param acceleration magnitude of acceleration\r
282          * @param angle relative to north, in degrees\r
283          */\r
284         public void accelerate(float acceleration, float angle) {\r
285                 this.acceleration = acceleration;\r
286                 this.velocityAngle = angle;\r
287                 this.velocityXFactor = (float)Math.sin(angle * MathHelper.DEG_TO_RAD);\r
288                 this.velocityYFactor = (float)Math.cos(angle * MathHelper.DEG_TO_RAD);\r
289         }\r
290         \r
291         /**\r
292          * Accelerates along a given angle to a terminal velocity\r
293          * \r
294          * @param acceleration magnitude of acceleration\r
295          * @param angle relative to north, in radians\r
296          * @param terminalVelocity maximum velocity to reach\r
297          */\r
298         public void accelerate(float acceleration, float angle, float terminalVelocity) {\r
299                 accelerate(acceleration, angle);\r
300                 this.terminalVelocity = terminalVelocity;\r
301                 useTerminalVelocity = true;\r
302         }\r
303         \r
304         /**\r
305          * Removes the limit on speed in the X direction\r
306          */\r
307         public void stopUsingTerminalSpeedX() {\r
308                 useTerminalSpeedX = false;\r
309         }\r
310         \r
311         /**\r
312          * Removes the limit on speed in the Y direction\r
313          */\r
314         public void stopUsingTerminalSpeedY() {\r
315                 useTerminalSpeedY = false;\r
316         }\r
317         \r
318         /**\r
319          * Removes the limit on speed in both X and Y directions\r
320          */\r
321         public void stopUsingTerminalSpeed() {\r
322                 useTerminalSpeedX = false;\r
323                 useTerminalSpeedY = false;\r
324         }\r
325         \r
326         /**\r
327          * @return TRUE if the DynamicObject is limited to a given speed in the X direction\r
328          */\r
329         public boolean isUsingTerminalSpeedX() {\r
330                 return useTerminalSpeedX;\r
331         }\r
332         \r
333         /**\r
334          * @return TRUE if the DynamicObject is limited to a given speed in the Y direction\r
335          */\r
336         public boolean isUsingTerminalSpeedY() {\r
337                 return useTerminalSpeedY;\r
338         }\r
339         \r
340         /**\r
341          * Removes the limit on velocity\r
342          */\r
343         public void stopUsingTerminalVelocity() {\r
344                 useTerminalVelocity = false;\r
345         }\r
346         \r
347         /**\r
348          * @return TRUE if the DynamicOject is limited to a given terminal velocity\r
349          */\r
350         public boolean isUsingTerminalVelocity() {\r
351                 return useTerminalVelocity;\r
352         }\r
353         \r
354         /**\r
355          * Removes the limit on angular velocity\r
356          */\r
357         public void stopUsingTerminalAngularVelocity() {\r
358                 useTerminalAngularVelocity = false;\r
359         }\r
360         \r
361         /**\r
362          * @return TRUE if the DynamicObject is limited to a given terminal angular velocity\r
363          */\r
364         public boolean isUsingTerminalAngularVelocity() {\r
365                 return useTerminalAngularVelocity;\r
366         }\r
367 \r
368         /**\r
369          * @return current acceleration to speed in X direction\r
370          */\r
371         public float getAccelerationX() {\r
372                 return accelerationX;\r
373         }\r
374         \r
375         /**\r
376          * @return current acceleration to speed in Y direction\r
377          */\r
378         public float getAccelerationY() {\r
379                 return accelerationY;\r
380         }\r
381 \r
382         /**\r
383          * @return current acceleration to velocity\r
384          */\r
385         public float getAcceleration() {\r
386                 return acceleration;\r
387         }\r
388         \r
389         /**\r
390          * @return angular acceleration\r
391          */\r
392         public float getAngularAcceleration() {\r
393                 return angularAcceleration;\r
394         }\r
395         \r
396         /**\r
397          * @return angular velocity\r
398          */\r
399         public float getAngularVelocity() {\r
400                 return angularVelocity;\r
401         }\r
402         \r
403         /**\r
404          * @return current angle at which the velocity is being applied\r
405          */\r
406         public float getVelocityAngle() {\r
407                 return velocityAngle;\r
408         }\r
409         \r
410         /**\r
411          * @return magnitude of the velocity\r
412          */\r
413         public float getVelocity() {\r
414                 return velocity;\r
415         }\r
416         \r
417         /**\r
418          * @return scalar speed in X direction\r
419          */\r
420         public float getSpeedX() {\r
421                 return speedX;\r
422         }\r
423         \r
424         /**\r
425          * @return scalar speed in Y direction\r
426          */\r
427         public float getSpeedY() {\r
428                 return speedY;\r
429         }\r
430         \r
431         /**\r
432          * @return terminal speed in X direction\r
433          */\r
434         public float getTerminalSpeedX() {\r
435                 return terminalSpeedX;\r
436         }\r
437         \r
438         /**\r
439          * @return terminal speed in Y direction\r
440          */\r
441         public float getTerminalSpeedY() {\r
442                 return terminalSpeedY;\r
443         }\r
444         \r
445         /**\r
446          * @return terminal velocity\r
447          */\r
448         public float getTerminalVelocity() {\r
449                 return terminalVelocity;\r
450         }\r
451         \r
452         /**\r
453          * @return terminal angular velocity\r
454          */\r
455         public float getTerminalAngularVelocity() {\r
456                 return terminalAngularVelocity;\r
457         }\r
458         \r
459         /**\r
460          * Sets the terminal speed in the X direction\r
461          * \r
462          * @param terminalSpeedX terminal speed in X\r
463          */\r
464         public void setTerminalSpeedX(float terminalSpeedX) {\r
465                 this.terminalSpeedX = terminalSpeedX;\r
466                 useTerminalSpeedX =true;\r
467         }\r
468         \r
469         /**\r
470          * Sets the terminal speed in the Y direction\r
471          * \r
472          * @param terminalSpeedY terminal speed in Y\r
473          */\r
474         public void setTerminalSpeedY(float terminalSpeedY) {\r
475                 this.terminalSpeedY = terminalSpeedY;\r
476                 useTerminalSpeedY = true;\r
477         }\r
478         \r
479         /**\r
480          * Sets the terminal speed in both basic directions\r
481          * \r
482          * @param terminalSpeedX terminal speed in X\r
483          * @param terminalSpeedY terminal speed in Y\r
484          */\r
485         public void setTerminalSpeed(float terminalSpeedX, float terminalSpeedY) {\r
486                 this.terminalSpeedX = terminalSpeedX;\r
487                 this.terminalSpeedY = terminalSpeedY;\r
488                 useTerminalSpeedX = true;\r
489                 useTerminalSpeedY = true;\r
490         }\r
491         \r
492         /**\r
493          * Sets the terminal velocity\r
494          * \r
495          * @param terminalVelocity terminal velocity\r
496          */\r
497         public void setTerminalVelocity(float terminalVelocity) {\r
498                 this.terminalVelocity = terminalVelocity;\r
499                 useTerminalVelocity = true;\r
500         }\r
501         \r
502         /**\r
503          * Sets the terminal angular velocity\r
504          * \r
505          * @param terminalAngularVelocity terminal angular velocity\r
506          */\r
507         public void setTerminalAngularVelocity(float terminalAngularVelocity) {\r
508                 this.terminalAngularVelocity = terminalAngularVelocity;\r
509                 useTerminalAngularVelocity = true;\r
510         }\r
511         \r
512         /**\r
513          * Sets the angular acceleration\r
514          * \r
515          * @param acceleration floating point, in degrees \r
516          */\r
517         public void setAngularAcceleration(float acceleration) {\r
518                 this.angularAcceleration = acceleration;\r
519         }\r
520         \r
521         /**\r
522          * Sets the angular velocity\r
523          * \r
524          * @param angularVelocity floating point, in degrees\r
525          */\r
526         public void setAngularVelocity(float angularVelocity) {\r
527                 this.angularVelocity = angularVelocity;\r
528         }\r
529         \r
530         /**\r
531          * Rotates the Sprite to a specific angle, over a given time\r
532          * \r
533          * @param angle angle, in radians, to rotate to\r
534          * @param direction the direction (using ROTATE_TO_ constants)\r
535          * @param time time (in milliseconds) \r
536          * @param type movement type, as defined in Movement\r
537          */\r
538         public void rotateTo(float angle, int direction, int time, int type) {\r
539                 if(isRotateTo) {\r
540                         if(parentScene.useInvoke) attemptInvoke("onRotateToCancel");\r
541                 }\r
542 \r
543                 angularVelocity = 0;\r
544                 angularAcceleration = 0;\r
545                 terminalAngularVelocity = 0;\r
546                 \r
547                 rotateToAngleStart = this.rotation;\r
548                 rotateToAngle = angle;\r
549                 rotateToDirection = direction;\r
550                 isRotateTo = true;\r
551                 rotateToType = type;\r
552                 rotateToStartTime = Time.loopTicks;\r
553                 rotateToTime = time;\r
554                 \r
555                 rotateToCallback = null;\r
556                 \r
557                 rotation = rotation % Movement.TWO_PI;\r
558 \r
559                 if(rotateToDirection == ROTATE_TO_AUTOMATIC) {\r
560                         if(rotation > 180f) {\r
561                                 if(angle > 180f) {\r
562                                         if(angle > rotation) {\r
563                                                 rotateToDirection = ROTATE_TO_ANTI_CLOCKWISE;\r
564                                         } else {\r
565                                                 rotateToDirection = ROTATE_TO_CLOCKWISE;\r
566                                         }\r
567                                 } else {\r
568                                         if(angle > rotation - 180) {\r
569                                                 rotateToDirection = ROTATE_TO_ANTI_CLOCKWISE;\r
570                                         } else {\r
571                                                 rotateToDirection = ROTATE_TO_CLOCKWISE;\r
572                                         }\r
573                                 }\r
574                         } else {\r
575                                 if(angle > 180f) {\r
576                                         if(angle > rotation + 180) {\r
577                                                 rotateToDirection = ROTATE_TO_ANTI_CLOCKWISE;\r
578                                                 rotateToAngleStart += 360;\r
579                                         } else {\r
580                                                 rotateToDirection = ROTATE_TO_CLOCKWISE;\r
581                                         }\r
582                                 } else {\r
583                                         if(angle > rotation) {\r
584                                                 rotateToDirection = ROTATE_TO_CLOCKWISE;\r
585                                         } else {\r
586                                                 rotateToDirection = ROTATE_TO_ANTI_CLOCKWISE;\r
587                                         }\r
588                                 }\r
589                         }\r
590                 }\r
591                 Debug.print("Rotating from " + rotation + " to " + angle + " by "+ rotateToDirection);\r
592         }\r
593 \r
594         \r
595         /**\r
596          * Rotates to a given angle over a period of time\r
597          * \r
598          * @param angle the final angle, in radians\r
599          * @param direction automatic, clockwise or anticlockwise - defined by ROTATE_TO_ constants\r
600          * @param time in milliseconds\r
601          * @param type movement type, through Movement constants\r
602          * @param callback Callback object for invoking\r
603          */\r
604         public void rotateTo(float angle, int direction, int time, int type, Callback callback) {\r
605                 rotateTo(angle, direction, time, type);\r
606                 rotateToCallback = callback;\r
607         }\r
608         \r
609         protected void onUpdateRotateTo() {\r
610                 float position = (float)(Time.loopTicks - rotateToStartTime) / (float)rotateToTime;\r
611                 float movementFactor = Movement.getPosition(position, rotateToType);\r
612                 if(position >= 1) {\r
613                         rotation = rotateToAngle;\r
614                         isRotateTo = false;\r
615                         if(parentScene.useInvoke) {\r
616                                 attemptInvoke("onRotateToComplete");\r
617                         }\r
618                         if(rotateToCallback != null) {\r
619                                 attemptInvoke(rotateToCallback);\r
620                         }\r
621                         angularVelocity = 0;\r
622                         angularAcceleration = 0;\r
623                         terminalAngularVelocity = 0;\r
624                         return;\r
625                 }\r
626                 \r
627                 if(rotateToDirection == ROTATE_TO_CLOCKWISE) {\r
628                         rotation = rotateToAngleStart + (rotateToAngle - rotateToAngleStart) * movementFactor;\r
629                 } else {\r
630                         rotation = rotateToAngleStart - (rotateToAngleStart - rotateToAngle) * movementFactor;\r
631                 }\r
632         }\r
633         \r
634         protected boolean isMoveTo = false;\r
635         protected float moveToStartX, moveToStartY, moveToFinalX, moveToFinalY;\r
636         protected int moveToType;\r
637         protected long moveToStartTime, moveToTime;\r
638         protected Callback moveToCallback;\r
639         \r
640         public void moveTo(float x, float y, long time, int type, Callback callback) {\r
641                 moveTo(x, y, time, type);\r
642                 moveToCallback = callback;\r
643         }\r
644 \r
645         /**\r
646          * Moves the DynamicObject to a given spot, in a given time using\r
647          * All previous motion is cancelled. It may be possible to apply your own velocity\r
648          * and acceleration changes while moveTo is running, though it should be avoided.\r
649          * \r
650          * @param x final X coordinate\r
651          * @param y final Y coordinate\r
652          * @param time the time \r
653          * @param type the movement type, from Movement constants\r
654          */\r
655         public void moveTo(float x, float y, long time, int type) {\r
656                 if(isMoveTo) {\r
657                         if(parentScene.useInvoke) {\r
658                                 attemptInvoke("onMoveToCancel");\r
659                         }\r
660                 }\r
661 \r
662                 accelerationX = 0;\r
663                 accelerationY = 0;\r
664                 acceleration = 0;\r
665                 speedX = 0;\r
666                 speedY = 0;\r
667                 velocity = 0;\r
668                 velocityXFactor = 0;\r
669                 velocityYFactor = 0;\r
670                 velocityAngle = 0;\r
671                 terminalSpeedX = 0;\r
672                 terminalSpeedY = 0;\r
673                 terminalVelocity = 0;           \r
674                 \r
675                 moveToStartX = this.getX();\r
676                 moveToStartY = this.getY();\r
677                 moveToFinalX = x;\r
678                 moveToFinalY = y;\r
679                 isMoveTo = true;\r
680                 moveToType = type;\r
681                 moveToStartTime = Time.loopTicks;\r
682                 moveToTime = time;\r
683                 \r
684                 moveToCallback = null;\r
685         }\r
686 \r
687         /**\r
688          * Linearly moves the DynamicObject to a given spot, in a given time using\r
689          * All previous motion is cancelled. It may be possible to apply your own velocity\r
690          * and acceleration changes while moveTo is running, though it should be avoided.\r
691          * If the object is already moving, the previous movements onCancel will be triggered if attached to a handler\r
692          * \r
693          * @param x final X coordinate\r
694          * @param y final Y coordinate\r
695          * @param time the time \r
696          */\r
697         public void moveTo(float x, float y, long time) {\r
698                 moveTo(x, y, time, Movement.LINEAR);\r
699         }\r
700         \r
701         protected void onUpdateMoveTo() {\r
702                 float position = (float)(Time.loopTicks - moveToStartTime) / (float)moveToTime;\r
703                 float movementFactor = Movement.getPosition(position, moveToType);\r
704                 if(position >= 1) {\r
705                         setX(moveToFinalX);\r
706                         setY(moveToFinalY);\r
707                         isMoveTo = false;\r
708                         if(moveToCallback != null) {\r
709                                 attemptInvoke(moveToCallback);\r
710                         }\r
711                         if(parentScene.useInvoke) {\r
712                                 attemptInvoke("onMoveToComplete");\r
713                         }\r
714                         accelerationX = 0;\r
715                         accelerationY = 0;\r
716                         acceleration = 0;\r
717                         speedX = 0;\r
718                         speedY = 0;\r
719                         velocity = 0;\r
720                         velocityXFactor = 0;\r
721                         velocityYFactor = 0;\r
722                         velocityAngle = 0;\r
723                         terminalSpeedX = 0;\r
724                         terminalSpeedY = 0;\r
725                         terminalVelocity = 0;\r
726                         return;\r
727                 }\r
728                 setX(moveToStartX + ((moveToFinalX - moveToStartX) * movementFactor));\r
729                 setY(moveToStartY + ((moveToFinalY - moveToStartY) * movementFactor));\r
730         }\r
731         \r
732         /**\r
733          * Adds a Modifier to this Sprite\r
734          * \r
735          * @param modifier valid Modifier object\r
736          * \r
737          * @return TRUE if there was room to add the Modifier, FALSE if it failed\r
738          */\r
739         public boolean addModifier(Modifier modifier) {\r
740                 for(int i = 0; i < MAX_MODIFIERS; i++) {\r
741                         if(this.modifier[i] == null) {\r
742                                 this.modifier[i] = modifier;\r
743                                 modifier.onCreate(this);\r
744                                 modifierCount++;\r
745                                 return true;\r
746                         }\r
747                 }\r
748                 Debug.warning("Tried addModifier, Sprite is full [" + MAX_MODIFIERS + "]");\r
749                 return false;\r
750         }\r
751         \r
752         /**\r
753          * Removes a Modifier from a Sprite (if it exists)\r
754          * \r
755          * @param modifier valid Modifier object\r
756          */\r
757         public void removeModifier(Modifier modifier) {\r
758                 for(int i = 0; i < MAX_MODIFIERS; i++) {\r
759                         if(this.modifier[i] == modifier) {\r
760                                 this.modifier[i] = null;\r
761                                 modifierCount--;\r
762                                 return;\r
763                         }\r
764                 }\r
765         }\r
766         \r
767         /**\r
768          * Clears all the Modifiers from the Sprite\r
769          */\r
770         public void clearModifiers() {\r
771                 for(int i = 0; i < MAX_MODIFIERS; i++) {\r
772                         modifier[i] = null;\r
773                 }\r
774         }\r
775 \r
776         /**\r
777          * Determines whether a Sprite overlaps with this one\r
778          * \r
779          * @param sprite valid Sprite object\r
780          * \r
781          * @return TRUE if overlapping, FALSE otherwise\r
782          */\r
783         public boolean intersects(Sprite sprite) {\r
784                 return MathHelper.intersects(this, sprite);\r
785         }\r
786         \r
787 }\r