Callbacks are working good now, modified and updated the MoveTo functions of DynamicO...
[rokon:rokon.git] / src / com / stickycoding / rokon / Scene.java
1 package com.stickycoding.rokon;\r
2 \r
3 import java.lang.reflect.InvocationTargetException;\r
4 import java.lang.reflect.Method;\r
5 import java.util.Arrays;\r
6 \r
7 import javax.microedition.khronos.opengles.GL10;\r
8 \r
9 import android.view.MotionEvent;\r
10 \r
11 /**\r
12  * Scene.java\r
13  * A Scene holds and prepares drawable objects or object groups\r
14  * \r
15  * @author Richard\r
16  */\r
17 public class Scene {\r
18         \r
19         public static final int SCENE_TEXTURE_COUNT = 32;\r
20         public static final int DEFAULT_LAYER_COUNT = 1;\r
21         public static final int DEFAULT_LAYER_OBJECT_COUNT = 32;\r
22 \r
23         protected Layer[] layer;\r
24         protected boolean loadedTextures;\r
25         protected int layerCount;\r
26         protected Window window = null;\r
27         protected Texture[] textures;\r
28         protected boolean useInvoke;\r
29 \r
30         public void onTouchDown(DrawableObject object, float x, float y, MotionEvent event) { }\r
31         public void onTouchUp(DrawableObject object, float x, float y, MotionEvent event) { }\r
32         public void onTouchMove(DrawableObject object, float x, float y, MotionEvent event) { }\r
33         public void onTouch(DrawableObject object, float x, float y, MotionEvent event) { }\r
34         public void onTouchDown(float x, float y, MotionEvent event) { }\r
35         public void onTouchMove(float x, float y, MotionEvent event) { }\r
36         public void onTouch(float x, float y, MotionEvent event) { }\r
37         public void onTouchUp(float x, float y, MotionEvent event) { }\r
38         \r
39         /**\r
40          * Triggers the Scene to begin invoking methods on certain events, this is not set by default.\r
41          * If the methods that are to be invoked don't exist, no exceptions will be raised.\r
42          */\r
43         public void useInvoke() {\r
44                 useInvoke = true;\r
45         }\r
46         \r
47         /**\r
48          * Stops the Scene from invoking methods on events, this is the default state\r
49          */\r
50         public void stopInvoke() {\r
51                 useInvoke = false;\r
52         }\r
53         \r
54         /**\r
55          * Invokes a method inside the Scene class, defined by given parameters.\r
56          * If no parameters exist, use the alternative invoke method\r
57          * \r
58          * @param methodName String\r
59          * @param params Class[]\r
60          * @param paramValues Object[]\r
61          * \r
62          * @return TRUE if successful, FALSE otherwise\r
63          */\r
64         public boolean invoke(String methodName, Class<?>[] params, Object[] paramValues) {\r
65                 for(Method m : this.getClass().getDeclaredMethods()) {\r
66                         if(m.getName().equals(methodName)) {\r
67                                 if(Arrays.equals(params, m.getParameterTypes())) {\r
68                                         try {\r
69                                                 m.invoke(this, paramValues);\r
70                                                 return true;\r
71                                         } catch (IllegalArgumentException e) {\r
72                                                 Debug.error("Invoking, IllegalArgument");\r
73                                                 e.printStackTrace();\r
74                                                 return false;\r
75                                         } catch (IllegalAccessException e) {\r
76                                                 Debug.error("Invoking, IllegalAccess");\r
77                                                 e.printStackTrace();\r
78                                                 return false;\r
79                                         } catch (InvocationTargetException e) {\r
80                                                 Debug.error("Invoking, IllegalTarget");\r
81                                                 e.printStackTrace();\r
82                                                 return false;\r
83                                         }\r
84                                 }\r
85                         }\r
86                 }\r
87                 return false;\r
88         }\r
89         \r
90         /**\r
91          * Invokes a method by parameters inside a Callback object\r
92          * \r
93          * @param callback valid Callback object\r
94          * @return TRUE if successful, FALSE otherwise\r
95          */\r
96         public boolean invoke(Callback callback) {\r
97                 if(callback.parameters == null) {\r
98                         return invoke(callback.methodName);\r
99                 } \r
100                 if(callback.parameterTypes == null) {\r
101                         return invoke(callback.methodName, callback.parameters);\r
102                 }\r
103                 return invoke(callback.methodName, callback.parameterTypes, callback.parameters);\r
104         }\r
105         \r
106         /**\r
107          * USE AT YOUR OWN RISK\r
108          * Invokes a method inside the Scene class, it selects the first matching method name and tries to pass on given parameters\r
109          * An error will be raised if this isn't the correct method. This routine is simply for those too lazy (or wanting to save\r
110          * on a little processing time) and are 100% sure there are no name conflicts.\r
111          * \r
112          * IllegalArgumentException may be passed to the Debug class, logcat will be notified - but there is no way to test at your end.\r
113          * \r
114          * @param methodName String\r
115          * @param paramValues Object[]\r
116          * \r
117          * @return TRUE if successful, FALSE otherwise\r
118          */\r
119         public boolean invoke(String methodName, Object[] paramValues) {\r
120                 for(Method m : this.getClass().getDeclaredMethods()) {\r
121                         if(m.getName().equals(methodName)) {\r
122                                 try {\r
123                                         m.invoke(this, paramValues);\r
124                                         return true;\r
125                                 } catch (IllegalArgumentException e) {\r
126                                         Debug.error("Invoking, IllegalArgument");\r
127                                         e.printStackTrace();\r
128                                         return false;\r
129                                 } catch (IllegalAccessException e) {\r
130                                         Debug.error("Invoking, IllegalAccess");\r
131                                         e.printStackTrace();\r
132                                         return false;\r
133                                 } catch (InvocationTargetException e) {\r
134                                         Debug.error("Invoking, IllegalTarget");\r
135                                         e.printStackTrace();\r
136                                         return false;\r
137                                 }\r
138                         }\r
139                 }\r
140                 return false;\r
141         }\r
142         \r
143         /**\r
144          * Invokes a method inside the Scene class, assuming there are no parameters to pass\r
145          * \r
146          * @param methodName String\r
147          * \r
148          * @return TRUE if successful, FALSE otherwise\r
149          */\r
150         public boolean invoke(String methodName) {\r
151                 for(Method m : this.getClass().getDeclaredMethods()) {\r
152                         if(m.getName().equals(methodName)) {\r
153                                 if(m.getParameterTypes().length == 0) {\r
154                                         try {\r
155                                                 m.invoke(this);\r
156                                                 return true;\r
157                                         } catch (IllegalArgumentException e) {\r
158                                                 Debug.error("Invoking, IllegalArgument");\r
159                                                 e.printStackTrace();\r
160                                                 return false;\r
161                                         } catch (IllegalAccessException e) {\r
162                                                 Debug.error("Invoking, IllegalAccess");\r
163                                                 e.printStackTrace();\r
164                                                 return false;\r
165                                         } catch (InvocationTargetException e) {\r
166                                                 Debug.error("Invoking, IllegalTarget");\r
167                                                 e.printStackTrace();\r
168                                                 return false;\r
169                                         }\r
170                                 }\r
171                         }\r
172                 }\r
173                 return false;\r
174         }\r
175         \r
176         protected void handleTouch(MotionEvent event) {\r
177                 event.setLocation(event.getX() * (Device.widthPixels / RokonActivity.gameWidth), event.getY() * (Device.heightPixels  / RokonActivity.gameHeight));\r
178                 onTouch(event.getX(), event.getY(), event);\r
179                 switch(event.getAction()) {\r
180                         case MotionEvent.ACTION_DOWN:\r
181                                 onTouchDown(event.getX(), event.getY(), event);\r
182                                 break;\r
183                         case MotionEvent.ACTION_UP:\r
184                                 onTouchUp(event.getX(), event.getY(), event);\r
185                                 break;\r
186                         case MotionEvent.ACTION_MOVE:\r
187                                 onTouch(event.getX(), event.getY(), event);\r
188                                 break;\r
189                 }\r
190                 for(int i = 0; i < layerCount; i++) {\r
191                         for(int j = 0; j < layer[i].maximumDrawableObjects; j++) {\r
192                                 DrawableObject object = layer[i].drawableObjects.get(j);\r
193                                 if(object != null && object.isTouchable) {\r
194                                         if(MathHelper.pointInRect(event.getX(), event.getY(), object.x, object.y, object.width, object.height)) {\r
195                                                 onTouch(object, event.getX(), event.getY(), event);\r
196                                                 if(object.getName() != null) {\r
197                                                         invoke(object.getName() + "_onTouch", new Class[] { float.class, float.class, MotionEvent.class }, new Object[] { event.getX(), event.getY(), event });\r
198                                                 }\r
199                                                 switch(event.getAction()) {\r
200                                                         case MotionEvent.ACTION_DOWN:\r
201                                                                 onTouchDown(object, event.getX(), event.getY(), event);\r
202                                                                 if(object.getName() != null) {\r
203                                                                         invoke(object.getName() + "_onTouchDown", new Class[] { float.class, float.class, MotionEvent.class }, new Object[] { event.getX(), event.getY(), event });\r
204                                                                 }\r
205                                                                 break;\r
206                                                         case MotionEvent.ACTION_UP:\r
207                                                                 onTouchUp(object, event.getX(), event.getY(), event);\r
208                                                                 if(object.getName() != null) {\r
209                                                                         invoke(object.getName() + "_onTouchUp", new Class[] { float.class, float.class, MotionEvent.class }, new Object[] { event.getX(), event.getY(), event });\r
210                                                                 }\r
211                                                                 break;\r
212                                                         case MotionEvent.ACTION_MOVE:\r
213                                                                 onTouch(object, event.getX(), event.getY(), event);\r
214                                                                 if(object.getName() != null) {\r
215                                                                         invoke(object.getName() + "_onTouchMove", new Class[] { float.class, float.class, MotionEvent.class }, new Object[] { event.getX(), event.getY(), event });\r
216                                                                 }\r
217                                                                 break;\r
218                                                 }\r
219                                         }\r
220                                 }\r
221                         }\r
222                 }\r
223         }\r
224         \r
225         /**\r
226          * Creates a new Scene with given layer count, and a corresponding maximum DrawableObject count \r
227          * \r
228          * @param layerCount maximum number of layers\r
229          * @param layerObjectCount maximum number of DrawableObjects per layer, the array length must match layerCount\r
230          */\r
231         public Scene(int layerCount, int[] layerObjectCount) {\r
232                 this.layerCount = layerCount;\r
233                 layer = new Layer[layerCount];\r
234                 for(int i = 0; i < layerCount; i++) {\r
235                         layer[i] = new Layer(this, layerObjectCount[i]);\r
236                 }\r
237                 prepareNewScene();\r
238         }\r
239         \r
240         /**\r
241          * Creates a new Scene with given layer count, all layers will have the same maximum number of DrawableObjects\r
242          * \r
243          * @param layerCount maximum number of layers\r
244          * @param layerObjectCount maximum number of DrawableObjects per layer\r
245          */\r
246         public Scene(int layerCount, int layerObjectCount) {\r
247                 this.layerCount = layerCount;\r
248                 layer = new Layer[layerCount];\r
249                 for(int i = 0; i < layerCount; i++) {\r
250                         layer[i] = new Layer(this, layerObjectCount);\r
251                 }\r
252                 prepareNewScene();\r
253         }\r
254         \r
255         /**\r
256          * Creates a new Scene with given layer count, and a default maximum DrawableObject count of DEFAULT_LAYER_OBJECT_COUNT\r
257          * \r
258          * @param layerCount maximum number of layers\r
259          */\r
260         public Scene(int layerCount) {\r
261                 this(layerCount, DEFAULT_LAYER_OBJECT_COUNT);\r
262         }\r
263         \r
264         /**\r
265          * Creates a new Scene with defaults, DEFAULT_LAYER_COUNT and DEFAULT_LAYER_OBJECT_COUNT\r
266          */\r
267         public Scene() {\r
268                 this(DEFAULT_LAYER_COUNT, DEFAULT_LAYER_OBJECT_COUNT);\r
269                 \r
270         }\r
271         \r
272         private void prepareNewScene() {\r
273                 textures = new Texture[SCENE_TEXTURE_COUNT];\r
274         }\r
275         \r
276         /**\r
277          * Flags a Texture to be loaded into this Scene\r
278          * This must be called before RokonActivity.setScene\r
279          * \r
280          * @param texture valid Texture object\r
281          */\r
282         public void useTexture(Texture texture) {\r
283                 for(int i = 0; i < textures.length; i++) {\r
284                         if(textures[i] == null) {\r
285                                 textures[i] = texture;\r
286                                 return;\r
287                         }\r
288                 }\r
289                 Debug.warning("Scene.useTexture", "Tried loading too many Textures onto the Scene, max is " + textures.length);\r
290         }\r
291         \r
292         /**\r
293          * Defines the active Window for this Scene\r
294          * If no Window is given, a default static view will be rendered \r
295          * \r
296          * @param window\r
297          */\r
298         public void setWindow(Window window) {\r
299                 if(window == null) {\r
300                         Debug.warning("Scene.setWindow", "Tried setting a NULL Window");\r
301                         return;\r
302                 }\r
303                 this.window = window;\r
304         }\r
305         \r
306         /**\r
307          * Removes the current active Window, returning it to NULL\r
308          */\r
309         public void removeWindow() {\r
310                 window = null;\r
311         }\r
312         \r
313         /**\r
314          * @return NULL if there is no Window associated with this Scene\r
315          */\r
316         public Window getWindow() {\r
317                 if(window == null)\r
318                         return null;\r
319                 return window;\r
320         }\r
321         \r
322         /**\r
323          * Fetches the Layer object associated with the given index\r
324          * \r
325          * @param index the index of the Layer\r
326          * @return NULL if invalid index is given\r
327          */\r
328         public Layer getLayer(int index) {\r
329                 if(index < 0 || index > layerCount) {\r
330                         Debug.warning("Scene.getLayer", "Tried fetching invalid layer (" + index + "), maximum is " + layerCount);\r
331                         return null;\r
332                 }\r
333                 return layer[index];\r
334         }\r
335         \r
336         /**\r
337          * Clears the DrawableObjects from all Layers\r
338          */\r
339         public void clear() {\r
340                 for(int i = 0; i < layerCount; i++) {\r
341                         layer[i].clear();\r
342                 }\r
343         }\r
344         \r
345         /**\r
346          * Clears all the DrawableObjects from a specified Layer\r
347          * \r
348          * @param index the index of the Layer\r
349          */\r
350         public void clearLayer(int index) {\r
351                 if(index <= 0 || index > layerCount) {\r
352                         Debug.warning("Scene.clearLayer", "Tried clearing invalid layer (" + index + "), maximum is " + layerCount);\r
353                         return;\r
354                 }\r
355                 layer[index].clear();\r
356         }\r
357         \r
358         /**\r
359          * Moves a Layer from one index to another, and shuffles the others up or down to accomodate\r
360          * \r
361          * @param startIndex the current index of the Layer\r
362          * @param endIndex the desired final index of the Layer\r
363          */\r
364         public void moveLayer(int startIndex, int endIndex) {\r
365                 if(startIndex == endIndex) {\r
366                         Debug.warning("Scene.moveLayer", "Tried moving a Layer to its own position, stupid");\r
367                         return;\r
368                 }\r
369                 if(startIndex <= 0 || startIndex > layerCount) {\r
370                         Debug.warning("Scene.moveLayer", "Tried moving an invalid Layer, startIndex=" + startIndex + ", maximum is " + layerCount);\r
371                         return;\r
372                 }\r
373                 if(endIndex <= 0 || endIndex > layerCount) {\r
374                         Debug.warning("Scene.moveLayer", "Tried moving an invalid Layer, endIndex=" + endIndex + ", maximum is " + layerCount);\r
375                         return;\r
376                 }\r
377                 Layer temporaryLayer = layer[startIndex];\r
378                 if(endIndex < startIndex) {\r
379                         for(int i = endIndex; i < startIndex; i++) {\r
380                                 layer[i + 1] = layer[i];\r
381                         }\r
382                         layer[endIndex] = temporaryLayer;\r
383                 }\r
384                 if(endIndex > startIndex) { \r
385                         for(int i = startIndex; i < endIndex; i++) {\r
386                                 layer[i] = layer[i + 1];\r
387                         }\r
388                         layer[endIndex] = temporaryLayer;\r
389                 }\r
390         }\r
391         \r
392         /**\r
393          * Switches the position of one Layer with another\r
394          * \r
395          * @param layer1 the index of the first Layer\r
396          * @param layer2 the index of the second Layer\r
397          */\r
398         public void switchLayers(int layer1, int layer2) {\r
399                 if(layer1 == layer2) {\r
400                         Debug.warning("Scene.switchLayers", "Tried switching the same Layer");\r
401                         return;\r
402                 }\r
403                 if(layer1 < 0 || layer1 > layerCount) {\r
404                         Debug.warning("Scene.switchLayers", "Tried switch an invalid Layer, layer1=" + layer1 + ", maximum is " + layerCount);\r
405                         return;\r
406                 }\r
407                 if(layer2 < 0 || layer2 > layerCount) {\r
408                         Debug.warning("Scene.switchLayers", "Tried switch an invalid Layer, layer2=" + layer2 + ", maximum is " + layerCount);\r
409                         return;\r
410                 }\r
411                 Layer temporaryLayer = layer[layer1];\r
412                 layer[layer1] = layer[layer2];\r
413                 layer[layer2] = temporaryLayer;\r
414         }\r
415         \r
416         /**\r
417          * Replaces a Layer object in this Scene\r
418          * \r
419          * @param index a valid index for a Layer, less than getLayerCount\r
420          * @param layer a valid Layer object to replace the existing Layer\r
421          */\r
422         public void setLayer(int index, Layer layer) {\r
423                 if(layer == null) {\r
424                         Debug.warning("Scene.setLayer", "Tried setting to a null Layer");\r
425                         return;\r
426                 }\r
427                 if(index < 0 || index > layerCount) {\r
428                         Debug.warning("Scene.setLayer", "Tried setting an invalid Layer, index=" + index + ", maximum is " + layerCount);\r
429                         return;\r
430                 }\r
431                 this.layer[index] = layer;\r
432         }\r
433         \r
434         /**\r
435          * Adds a DrawableObject to the first (0th) Layer\r
436          * \r
437          * @param drawableObject a valid DrawableObject\r
438          */\r
439         public void add(DrawableObject drawableObject) {\r
440                 layer[0].add(drawableObject);\r
441         }\r
442         \r
443         /**\r
444          * Adds a DrawableObject to a given Layer\r
445          * \r
446          * @param layerIndex a valid index of a Layer\r
447          * @param drawableObject a valid DrawableObject\r
448          */\r
449         public void add(int layerIndex, DrawableObject drawableObject) {\r
450                 if(layerIndex < 0 || layerIndex > layerCount) {\r
451                         Debug.warning("Scene.add", "Tried adding to an invalid Layer, layerIndex=" + layerIndex + ", maximum is " + layerCount);\r
452                         return;\r
453                 }\r
454                 if(drawableObject == null) {\r
455                         Debug.warning("Scene.add", "Tried adding a NULL DrawableObject");\r
456                         return;\r
457                 }\r
458                 layer[layerIndex].add(drawableObject);\r
459         }\r
460         \r
461         /**\r
462          * Removes a DrawableObject from the Scene\r
463          * \r
464          * @param drawableObject a valid DrawableObject\r
465          */\r
466         public void remove(DrawableObject drawableObject) {\r
467                 drawableObject.remove();\r
468         }\r
469         \r
470         protected void onUpdate() {\r
471                 \r
472         }\r
473         \r
474         protected void onGameLoop() {\r
475                 \r
476         }\r
477         \r
478         protected void onSetScene() {\r
479                 loadedTextures = false;\r
480         }\r
481         \r
482         protected void onEndScene() {\r
483                 \r
484         }\r
485         \r
486         protected void onLoadTextures(GL10 gl) {\r
487                 Debug.print("Loading textures onto the Scene");\r
488                 for(int i = 0; i < textures.length; i++) {\r
489                         if(textures[i] != null) {\r
490                                 textures[i].onLoadTexture(gl);\r
491                                 textures[i] = null;\r
492                         }\r
493                 }\r
494                 loadedTextures = true;\r
495         }\r
496         \r
497         protected void onDraw(GL10 gl) {\r
498                 gl.glClear(GL10.GL_COLOR_BUFFER_BIT);\r
499         gl.glMatrixMode(GL10.GL_MODELVIEW);\r
500         gl.glLoadIdentity();\r
501                 for(int i = 0; i < layerCount; i++) {\r
502                         layer[i].onDraw(gl);\r
503                 }\r
504         }\r
505         \r
506 }\r