/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * AndroidWorld Library, Copyright 2011 Bryan Chadwick * * * * FILE: ./android/world/World.java * * * * This file is part of AndroidWorld. * * * * AndroidWorld is free software: you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation, either version * * 3 of the License, or (at your option) any later version. * * * * AndroidWorld is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with AndroidWorld. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package android.world; import android.app.Activity; import android.image.Scene; /** * * * A Class representing a World and the related methods for drawing the world * and handling various events. In order to implement a functioning World you * must extend this class, and implement an {@link android.world.World#onDraw onDraw} * method. Other handler methods ({@link android.world.World#tickRate tickRate}, {@link android.world.World#onTick onTick}, * {@link android.world.World#onMouse onMouse}, {@link android.world.World#onKey onKey}, {@link android.world.World#onRelease onRelease}, * {@link android.world.World#onOrientation onOrientation}, {@link android.world.World#stopWhen stopWhen}, * and {@link android.world.World#lastScene lastScene}) are optional, and can be overridden to add * new functionality. *

* See the individual methods for detailed documentation. *

* *

*

Extending World

*
* *

* Developing an Android application is a bit more work, since it requires the * Android development kit for Eclipse. After that, you can create an * Android Project and fill in all the parameters. The World/VoidWorld classes * only require a simple hook to be added to the application's Activity. *

* * Below is a simple example of a World that adds a new point at each mouse click. The world * contains a {@link android.image.Scene Scene} and a new {@link android.image.Circle Circle} is placed for each * "button-down" event received. The World is created in the * class that extends Activity. * *
   
 *        import android.app.Activity;
 *        import android.os.Bundle;
 *        import android.view.Display;
 *       
 *        import android.image.*;
 *        import android.world.World;
 *       
 *        public class MousePoints extends Activity{
 *           // Called when the activity is first created.
 *           public void onCreate(Bundle savedState) {
 *              super.onCreate(savedState);
 *               
 *              Display dis = getWindowManager().getDefaultDisplay();       
 *               
 *              // Create and start the World 
 *              new MousePointsWorld(new EmptyScene(dis.getWidth(), dis.getHeight()-50))
 *                      .bigBang(this);        
 *           }
 *        }
 *       
 *        class MousePointsWorld extends World{
 *            Scene scene;
 *       
 *            MousePointsWorld(Scene scene){
 *                this.scene = scene;    
 *            }
 *       
 *            public Scene onDraw(){ return this.scene; }
 *       
 *            public World onMouse(int x, int y, String me){
 *                if(!me.equals("button-down")){
 *                    return this;
 *                }else{
 *                    return new MousePointsWorld(
 *                            this.scene.placeImage(new Circle(20, "solid", "red")
 *                                         .overlay(new Circle(20, "outline", "black")), x, y));
 *                }
 *            }
 *        }
 * 
* * After a few finger-taps, the device will look something like this:

* * *
*

*/ public abstract class World{ /** The BigBang/Handler */ private BigBang bigbang; /** Default Tick rate for the world: ~33 frames per second */ public static double DEFAULT_TICK_RATE = 0.03; /** Mouse down (button-down) event String */ public static String MOUSE_DOWN = BigBang.MOUSE_DOWN; /** Mouse up (button-up) event String */ public static String MOUSE_UP = BigBang.MOUSE_UP; /** Mouse motion (move) event String */ public static String MOUSE_MOVE = BigBang.MOUSE_MOVE; /** Mouse down & move (drag) event String */ public static String MOUSE_DRAG = BigBang.MOUSE_DRAG; /** Key arrow-up event String */ public static String KEY_ARROW_UP = BigBang.KEY_ARROW_UP; /** Key arrow-down event String */ public static String KEY_ARROW_DOWN = BigBang.KEY_ARROW_RIGHT; /** Key arrow-left event String */ public static String KEY_ARROW_LEFT = BigBang.KEY_ARROW_LEFT; /** Key arrow-right event String */ public static String KEY_ARROW_RIGHT = BigBang.KEY_ARROW_RIGHT; /** Menu Key event String. The menu key will usually be intercepted to open a save dialog * to enable the capture of application/game screen-shots. */ public static String KEY_MENU = BigBang.KEY_MENU; /** Search Key event String */ public static String KEY_SEARCH = BigBang.KEY_SEARCH; /** Return a visualization of this World as a {@link android.image.Scene Scene}. * See {@link android.image.EmptyScene}, {@link android.image.Scene#placeImage(Image, int, int)}, and * {@link android.image.Scene#addLine(int, int, int, int, String)} for documentation on * constructing Scenes */ public abstract Scene onDraw(); /** Return the tick rate for this World in seconds. For example, * 0.5 means two tick. The rate is only accessed when * bigBang() is initially called and the window is created. */ public double tickRate(){ return DEFAULT_TICK_RATE; } /** Produce a (possibly) new World based on the Tick of the clock. This * method is called to get the next world on each clock tick.*/ public World onTick(){ return this; } /** Produce a (possibly) new World when a touch event is triggered. * x and y are the location of the event on the device screen, * and event is a String that describes what kind of event * occurred. * *

* In addition to the normal World events (button-down/up) Android devices * include a "long-button-down" event, for when the * the user does a long press (touch and hold). *

*

* Possible Mouse Events * * * * * * * * * * * *
"button-down" : The user presses the touch screen of the device
"long-button-down" : The user presses and holds on the touch screen of the device
"button-up" : The user releases the touch screen of the device
"move" : The user moves the mouse in the World window
"drag" : The user touches and moves on the touch screen of the device
*

*/ public World onMouse(int x, int y, String event){ return this; } /** Produce a (possibly) new World when a key is * pressed. The given event is a String that * describes what key was pressed. * *

* Special Keys * * * * * * * * * *
"up" : The user presses the up-arrow key
"down" : The user presses the down-arrow key
"left" : The user presses the left-arrow key
"right" : The user presses the right-arrow key
* * Other keys generate a single character String that * represents the key pressed. For example, Pressing the B key on * the keyboard generates "b" as an event. * If the shift key is held while pressing B then "B" is generated. *

*/ public World onKey(String event){ return this; } /** Produce a (possibly) new World when a key is released. The given event * is a String that describes which key was released. * *

* Special Keys * * * * * * * * * *
"up" : The user presses the up-arrow key
"down" : The user presses the down-arrow key
"left" : The user presses the left-arrow key
"right" : The user presses the right-arrow key
* * Other keys generate a single character String that * represents the key released. For example, Pressing then releasing the B key on * the keyboard generates "b" as an onKey event and again * as an onRelease event. If the shift key is held while pressing/releasing B then "B" is generated. *

*/ public World onRelease(String event){ return this; } /** Determine if the World/interaction/animation should be * stopped. Returning a value of true * discontinues all events (mouse, key, ticks) and causes {@link * android.world.World#lastScene} to be used to draw the final * Scene. */ public boolean stopWhen(){ return false; } /** Returns the Scene that should be displayed when the * interaction/animation completes ({@link android.world.World#stopWhen} * returns true). */ public Scene lastScene(){ return this.onDraw(); } /** Produce a (possibly) new World when a device orientation event is triggered. * x, y, and z make-up the new orientation vector * for the device. When the device is resting on a flat, level surface the * orientation should be entirly in the z direction (typically * straight out the the back of the device). * *

* If you are only concerned with the "down" angle (direction of down * with respect to the screen) you can calculate it with a method as follows: *

     *      double down(double x, double y, double z){
     *         double ang = Math.acos(x/Math.sqrt(x*x + y*y))+Math.PI;
     *         if(y < 0)return 2*Math.PI-ang;
     *         return ang;
     *      }
     *   
*

*/ public World onOrientation(double x, double y, double z){ return this; } /** Kick off the interaction/animation. This method returns the final * state of the world after the user closes the World window. */ public World bigBang(Activity act){ return (World)this.makeBigBang().bigBang(act); } /** Kick off the interaction/animation in LANDSCAPE mode. */ public World bigBangLandscape(Activity act){ return (World)this.makeBigBang().bigBangLandscape(act); } /** Kick off the interaction/animation FULLSCREEN mode. This method returns the final * state of the world after the user closes the World window. */ public World bigBangFullscreen(Activity act){ return (World)this.makeBigBang().bigBangFullscreen(act); } /** Kick off the interaction/animation in FULLSCREEN/LANDSCAPE mode. */ public World bigBangLandscapeFullscreen(Activity act){ return (World)this.makeBigBang().bigBangLandscapeFullscreen(act); } /** Get a bigbang instance for this World */ private BigBang makeBigBang(){ this.bigbang = new BigBang(this) .onDraw(new WorldDraw()) .onTick(new WorldTick(), tickRate()) .onMouse(new WorldMouse()) .onKey(new WorldKey()) .onRelease(new WorldRelease()) .stopWhen(new WorldStop()) .lastScene(new WorldLast()) .orientation(new WorldOrient()); return this.bigbang; } /** Use to Disable Screen Shots */ public static void noScreenShots(){ BigBang.Handler.screenShots = false; } /** Use to temperarily disable onTick/interactions */ public void pause(){ this.bigbang.pause(); } /** Use to renable onTick/interactions */ public void unpause(){ this.bigbang.unpause(); } /** Wrapper for OnDraw callback */ private static class WorldDraw{ @SuppressWarnings("unused") Scene apply(World w){ return w.onDraw(); } } /** Wrapper for OnTick callback */ private static class WorldTick{ @SuppressWarnings("unused") World apply(World w){ return w.onTick(); } } /** Wrapper for OnMouse callback */ private static class WorldMouse{ @SuppressWarnings("unused") World apply(World w, int x, int y, String me) { return w.onMouse(x,y,me); } } /** Wrapper for OnKey callback */ private static class WorldKey{ @SuppressWarnings("unused") World apply(World w, String ke){ return w.onKey(ke); } } /** Wrapper for OnRelease callback */ private static class WorldRelease{ @SuppressWarnings("unused") World apply(World w, String ke){ return w.onRelease(ke); } } /** Wrapper for StopWhen callback */ private static class WorldStop{ @SuppressWarnings("unused") boolean apply(World w){ return w.stopWhen(); } } /** Wrapper for LastScene callback */ private static class WorldLast{ @SuppressWarnings("unused") Scene apply(World w){ return w.lastScene(); } } /** Wrapper for LastScene callback */ private static class WorldOrient{ @SuppressWarnings("unused") World apply(World w, float x, float y, float z){ return w.onOrientation(x,y,z); } } }