/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * AndroidWorld Library, Copyright 2011 Bryan Chadwick * * * * FILE: ./android/world/VoidWorld.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; import android.util.Log; /** * * * A Class representing an imperative 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.VoidWorld#onDraw onDraw} * method. Other handler methods ({@link android.world.VoidWorld#tickRate tickRate}, {@link android.world.VoidWorld#onTick onTick}, * {@link android.world.VoidWorld#onMouse onMouse}, {@link android.world.VoidWorld#onKey onKey}, {@link android.world.VoidWorld#onRelease onRelease}, * {@link android.world.VoidWorld#onOrientation onOrientation}, {@link android.world.VoidWorld#stopWhen stopWhen}, * and {@link android.world.VoidWorld#lastScene lastScene}) are optional, and can be overridden to add new functionality. *

* See the individual methods for detailed documentation. *

* *

*

Extending VoidWorld

*
*

* 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 VoidWorld 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.VoidWorld;
 *       
 *        public class VoidMousePoints 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 MousePointsVoidWorld(dis.getWidth(), dis.getHeight()-50);
 *                       .bigBang(this);        
 *            }
 *        }
 *       
 *        public class MousePointsVoidWorld extends VoidWorld{
 *            int WIDTH;
 *            int HEIGHT
 *            Scene scene;
 *     
 *            MousePointsVoidWorld(int WIDTH, int HEIGHT){
 *                 this.WIDTH = WIDTH;
 *                 this.HEIGHT = HEIGHT;
 *                 this.scene = new EmptyScene(WIDTH, HEIGHT);
 *            }
 *            
 *            public Scene onDraw(){ return this.scene; }
 *     
 *            public void onMouse(int x, int y, String me){
 *                if(me.equals("button-down")){
 *                    this.scene = 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 VoidWorld{ /** 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(android.image.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; } /** Change this World based on the Tick of the clock. This * method is called to get the update the World on each clock tick.*/ public void onTick(){ } /** Change this 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 void onMouse(int x, int y, String event){ } /** Change this World when a key event is * triggered. The given event is a String that * describes which key was pressed. * *

* Special Key * * * * * * * * * *
"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 void onKey(String event){ } /** Change this 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 void onRelease(String event){ } /** Change this 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 entirely 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 void onOrientation(double x, double y, double z){ } /** 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.VoidWorld#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.VoidWorld#stopWhen} * returns true). */ public Scene lastScene(){ return this.onDraw(); } /** Kick off the interaction/animation in PORTRATE mode. This method returns the final * state of the world after the user closes the World window. */ public VoidWorld bigBang(Activity act){ return (VoidWorld)this.makeBigBang().bigBang(act); } /** Kick off the interaction/animation in LANDSCAPE mode. */ public VoidWorld bigBangLandscape(Activity act){ return (VoidWorld)this.makeBigBang().bigBangLandscape(act); } /** Kick off the interaction/animation in FULLSCREEN/PORTRATE mode. This method returns the final * state of the world after the user closes the World window. */ public VoidWorld bigBangFullscreen(Activity act){ return (VoidWorld)this.makeBigBang().bigBangFullscreen(act); } /** Kick off the interaction/animation in FULLSCREEN/LANDSCAPE mode. */ public VoidWorld bigBangLandscapeFullscreen(Activity act){ return (VoidWorld)this.makeBigBang().bigBangLandscapeFullscreen(act); } /** Get a bigbang instance for this VoidWorld */ public 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(){ Log.d("BIGBANG","HERE: "+this.bigbang); 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(VoidWorld w){ return w.onDraw(); } } /** Wrapper for OnTick callback */ private static class WorldTick{ @SuppressWarnings("unused") VoidWorld apply(VoidWorld w){ w.onTick(); return w; } } /** Wrapper for OnMouse callback */ private static class WorldMouse{ @SuppressWarnings("unused") VoidWorld apply(VoidWorld w, int x, int y, String me) { w.onMouse(x,y,me); return w; } } /** Wrapper for OnKey callback */ private static class WorldKey{ @SuppressWarnings("unused") VoidWorld apply(VoidWorld w, String ke){ w.onKey(ke); return w; } } /** Wrapper for OnKey callback */ private static class WorldRelease{ @SuppressWarnings("unused") VoidWorld apply(VoidWorld w, String ke){ w.onRelease(ke); return w; } } /** Wrapper for StopWhen callback */ private static class WorldStop{ @SuppressWarnings("unused") boolean apply(VoidWorld w){ return w.stopWhen(); } } /** Wrapper for LastScene callback */ private static class WorldLast{ @SuppressWarnings("unused") Scene apply(VoidWorld w){ return w.lastScene(); } } /** Wrapper for LastScene callback */ private static class WorldOrient{ @SuppressWarnings("unused") VoidWorld apply(VoidWorld w, float x, float y, float z){ w.onOrientation(x,y,z); return w; } } /** Make sure that changes are redrawn every time */ public boolean equals(Object o){ return false; } }