OSDN Git Service

Fixed stage clipping when using glViewport. Fixed clicking outside of stage.
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / scenes / scene2d / Actor.java
index 53c5007..83d02f4 100644 (file)
@@ -22,18 +22,31 @@ import com.badlogic.gdx.math.MathUtils;
 import com.badlogic.gdx.math.Rectangle;\r
 import com.badlogic.gdx.math.Vector2;\r
 import com.badlogic.gdx.scenes.scene2d.InputEvent.Type;\r
+import com.badlogic.gdx.scenes.scene2d.actions.Actions;\r
+import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;\r
+import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;\r
 import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;\r
 import com.badlogic.gdx.utils.Array;\r
 import com.badlogic.gdx.utils.DelayedRemovalArray;\r
 import com.badlogic.gdx.utils.GdxRuntimeException;\r
 import com.badlogic.gdx.utils.Pools;\r
 \r
-/** 2D scene graph node. An actor has a position, rectangular size, origin, scale, rotation, and color. The position corresponds to\r
- * the unrotated, unscaled bottom left corner of the actor. The position is relative to the actor's parent. The origin is relative\r
- * to the position and is used for scale and rotation.\r
+/** 2D scene graph node. An actor has a position, rectangular size, origin, scale, rotation, Z index, and color. The position\r
+ * corresponds to the unrotated, unscaled bottom left corner of the actor. The position is relative to the actor's parent. The\r
+ * origin is relative to the position and is used for scale and rotation.\r
  * <p>\r
- * An actor also has a list of actions that can manipulate the actor over time, and a list of listeners that are notified of\r
- * events the actor receives.\r
+ * An actor has a list of in-progress {@link Action actions} that are applied to the actor (over time). These are generally used to\r
+ * change the presentation of the actor (moving it, resizing it, etc). See {@link #act(float)} and {@link Action}.\r
+ * <p>\r
+ * An actor has two kinds of listeners associated with it: "capture" and regular. The listeners are notified of events the actor\r
+ * or its children receive. The capture listeners are designed to allow a parent or container actor to hide events from child\r
+ * actors. The regular listeners are designed to allow an actor to respond to events that have been delivered. See {@link #fire}\r
+ * for more details.\r
+ * <p>\r
+ * An {@link InputListener} can receive all the basic input events, and more complex listeners (like {@link ClickListener} and\r
+ * {@link ActorGestureListener}) can listen for and combine primitive events and recognize complex interactions like multi-click\r
+ * or pinch.\r
+ * \r
  * @author mzechner\r
  * @author Nathan Sweet */\r
 public class Actor {\r
@@ -46,12 +59,12 @@ public class Actor {
        private String name;\r
        private Touchable touchable = Touchable.enabled;\r
        private boolean visible = true;\r
-       private float x, y;\r
-       private float width, height;\r
-       private float originX, originY;\r
-       private float scaleX = 1, scaleY = 1;\r
-       private float rotation;\r
-       private final Color color = new Color(1, 1, 1, 1);\r
+       float x, y;\r
+       float width, height;\r
+       float originX, originY;\r
+       float scaleX = 1, scaleY = 1;\r
+       float rotation;\r
+       final Color color = new Color(1, 1, 1, 1);\r
 \r
        /** Draws the actor. The SpriteBatch is configured to draw in the parent's coordinate system.\r
         * {@link SpriteBatch#draw(com.badlogic.gdx.graphics.g2d.TextureRegion, float, float, float, float, float, float, float, float, float)\r
@@ -60,7 +73,7 @@ public class Actor {
         * {@link SpriteBatch#begin()} must be called before the method returns.\r
         * <p>\r
         * The default implementation does nothing.\r
-        * @param parentAlpha Should be multipied with the actor's alpha, allowing a parent's alpha to affect all children. */\r
+        * @param parentAlpha Should be multiplied with the actor's alpha, allowing a parent's alpha to affect all children. */\r
        public void draw (SpriteBatch batch, float parentAlpha) {\r
        }\r
 \r
@@ -69,13 +82,12 @@ public class Actor {
         * The default implementation calls {@link Action#act(float)} on each action and removes actions that are complete.\r
         * @param delta Time in seconds since the last frame. */\r
        public void act (float delta) {\r
-               for (int i = 0, n = actions.size; i < n; i++) {\r
+               for (int i = 0; i < actions.size; i++) {\r
                        Action action = actions.get(i);\r
-                       if (action.act(delta)) {\r
+                       if (action.act(delta) && i < actions.size) {\r
                                actions.removeIndex(i);\r
                                action.setActor(null);\r
                                i--;\r
-                               n--;\r
                        }\r
                }\r
        }\r
@@ -83,11 +95,15 @@ public class Actor {
        /** Sets this actor as the event {@link Event#setTarget(Actor) target} and propagates the event to this actor and ancestor\r
         * actors as necessary. If this actor is not in the stage, the stage must be set before calling this method.\r
         * <p>\r
-        * Events are fired in 2 phases. The first phase notifies listeners on each actor starting at the root and propagating downward\r
-        * to (and including) this actor. The second phase notifes listeners on each actor starting at this actor and, if\r
-        * {@link Event#getBubbles()} is true, propagating upward to the root. If the event is {@link Event#stop() stopped} at any time,\r
-        * it will not propagate to the next actor.\r
-        * @return true of the event was {@link Event#cancel() cancelled}. */\r
+        * Events are fired in 2 phases.\r
+        * <ol>\r
+        * <li>The first phase (the "capture" phase) notifies listeners on each actor starting at the root and propagating downward to\r
+        * (and including) this actor.</li>\r
+        * <li>The second phase notifies listeners on each actor starting at this actor and, if {@link Event#getBubbles()} is true,\r
+        * propagating upward to the root.</li>\r
+        * </ol>\r
+        * If the event is {@link Event#stop() stopped} at any time, it will not propagate to the next actor.\r
+        * @return true if the event was {@link Event#cancel() cancelled}. */\r
        public boolean fire (Event event) {\r
                if (event.getStage() == null) event.setStage(getStage());\r
                event.setTarget(this);\r
@@ -168,9 +184,11 @@ public class Actor {
         * {@link #isVisible() visible}, or null if no actor was hit. The point is specified in the actor's local coordinate system (0,0\r
         * is the bottom left of the actor and width,height is the upper right).\r
         * <p>\r
-        * This method is used to delegate touchDown events. If this method returns null, touchDown will not occur.\r
+        * This method is used to delegate touchDown, mouse, and enter/exit events. If this method returns null, those events will not\r
+        * occur on this Actor.\r
         * <p>\r
         * The default implementation returns this actor if the point is within this actor's bounds.\r
+        * \r
         * @param touchable If true, the hit detection will respect the {@link #setTouchable(Touchable) touchability}.\r
         * @see Touchable */\r
        public Actor hit (float x, float y, boolean touchable) {\r
@@ -185,6 +203,10 @@ public class Actor {
                return false;\r
        }\r
 \r
+       /** Add a listener to receive events that {@link #hit(float, float, boolean) hit} this actor. See {@link #fire(Event)}.\r
+        * \r
+        * @see InputListener\r
+        * @see ClickListener */\r
        public boolean addListener (EventListener listener) {\r
                if (!listeners.contains(listener, true)) {\r
                        listeners.add(listener);\r
@@ -236,6 +258,18 @@ public class Actor {
                actions.clear();\r
        }\r
 \r
+       /** Removes all listeners on this actor. */\r
+       public void clearListeners () {\r
+               listeners.clear();\r
+               captureListeners.clear();\r
+       }\r
+\r
+       /** Removes all actions and listeners on this actor. */\r
+       public void clear () {\r
+               clearActions();\r
+               clearListeners();\r
+       }\r
+\r
        /** Returns the stage that this actor is currently in, or null if not in a stage. */\r
        public Stage getStage () {\r
                return stage;\r
@@ -254,7 +288,7 @@ public class Actor {
                while (true) {\r
                        if (parent == null) return false;\r
                        if (parent == actor) return true;\r
-                       parent = parent.getParent();\r
+                       parent = parent.parent;\r
                }\r
        }\r
 \r
@@ -264,7 +298,7 @@ public class Actor {
                while (true) {\r
                        if (actor == null) return false;\r
                        if (actor == this) return true;\r
-                       actor = actor.getParent();\r
+                       actor = actor.parent;\r
                }\r
        }\r
 \r
@@ -278,7 +312,7 @@ public class Actor {
                return parent;\r
        }\r
 \r
-       /** Called by the framework when an actor is added to a group.\r
+       /** Called by the framework when an actor is added to or removed from a group.\r
         * @param parent May be null if the actor has been removed from the parent. */\r
        protected void setParent (Group parent) {\r
                this.parent = parent;\r
@@ -320,13 +354,13 @@ public class Actor {
 \r
        /** Sets the x and y. */\r
        public void setPosition (float x, float y) {\r
-               setX(x);\r
-               setY(y);\r
+               this.x = x;\r
+               this.y = y;\r
        }\r
 \r
        public void translate (float x, float y) {\r
-               setX(this.x + x);\r
-               setY(this.y + y);\r
+               this.x += x;\r
+               this.y += y;\r
        }\r
 \r
        public float getWidth () {\r
@@ -347,38 +381,38 @@ public class Actor {
 \r
        /** Returns y plus height. */\r
        public float getTop () {\r
-               return getY() + getHeight();\r
+               return y + height;\r
        }\r
 \r
        /** Returns x plus width. */\r
        public float getRight () {\r
-               return getX() + getWidth();\r
+               return x + width;\r
        }\r
 \r
        /** Sets the width and height. */\r
        public void setSize (float width, float height) {\r
-               setWidth(width);\r
-               setHeight(height);\r
+               this.width = width;\r
+               this.height = height;\r
        }\r
 \r
        /** Adds the specified size to the current size. */\r
        public void size (float size) {\r
-               setWidth(width + size);\r
-               setHeight(height + size);\r
+               width += size;\r
+               height += size;\r
        }\r
 \r
        /** Adds the specified size to the current size. */\r
        public void size (float width, float height) {\r
-               setWidth(this.width + width);\r
-               setHeight(this.height + height);\r
+               this.width += width;\r
+               this.height += height;\r
        }\r
 \r
        /** Set bounds the x, y, width, and height. */\r
        public void setBounds (float x, float y, float width, float height) {\r
-               setX(x);\r
-               setY(y);\r
-               setWidth(width);\r
-               setHeight(height);\r
+               this.x = x;\r
+               this.y = y;\r
+               this.width = width;\r
+               this.height = height;\r
        }\r
 \r
        public float getOriginX () {\r
@@ -399,8 +433,8 @@ public class Actor {
 \r
        /** Sets the originx and originy. */\r
        public void setOrigin (float originX, float originY) {\r
-               setOriginX(originX);\r
-               setOriginY(originY);\r
+               this.originX = originX;\r
+               this.originY = originY;\r
        }\r
 \r
        public float getScaleX () {\r
@@ -421,26 +455,26 @@ public class Actor {
 \r
        /** Sets the scalex and scaley. */\r
        public void setScale (float scale) {\r
-               setScaleX(scale);\r
-               setScaleY(scale);\r
+               this.scaleX = scale;\r
+               this.scaleY = scale;\r
        }\r
 \r
        /** Sets the scalex and scaley. */\r
        public void setScale (float scaleX, float scaleY) {\r
-               setScaleX(scaleX);\r
-               setScaleY(scaleY);\r
+               this.scaleX = scaleX;\r
+               this.scaleY = scaleY;\r
        }\r
 \r
        /** Adds the specified scale to the current scale. */\r
        public void scale (float scale) {\r
-               setScaleX(scaleX + scale);\r
-               setScaleY(scaleY + scale);\r
+               scaleX += scale;\r
+               scaleY += scale;\r
        }\r
 \r
        /** Adds the specified scale to the current scale. */\r
        public void scale (float scaleX, float scaleY) {\r
-               setScaleX(this.scaleX + scaleX);\r
-               setScaleY(this.scaleY + scaleY);\r
+               this.scaleX += scaleX;\r
+               this.scaleY += scaleY;\r
        }\r
 \r
        public float getRotation () {\r
@@ -453,7 +487,7 @@ public class Actor {
 \r
        /** Adds the specified rotation to the current rotation. */\r
        public void rotate (float amountInDegrees) {\r
-               setRotation(rotation + amountInDegrees);\r
+               rotation += amountInDegrees;\r
        }\r
 \r
        public void setColor (Color color) {\r
@@ -464,7 +498,7 @@ public class Actor {
                color.set(r, g, b, a);\r
        }\r
 \r
-       /** Returns the actor's color, which is mutable. */\r
+       /** Returns the color the actor will be tinted when drawn. The returned instance can be modified to change the color. */\r
        public Color getColor () {\r
                return color;\r
        }\r
@@ -494,7 +528,7 @@ public class Actor {
         * Setting a z-index less than zero is invalid. */\r
        public void setZIndex (int index) {\r
                if (index < 0) throw new IllegalArgumentException("ZIndex cannot be < 0.");\r
-               Group parent = getParent();\r
+               Group parent = this.parent;\r
                if (parent == null) return;\r
                Array<Actor> children = parent.getChildren();\r
                if (children.size == 1) return;\r
@@ -508,14 +542,14 @@ public class Actor {
        /** Returns the z-index of this actor.\r
         * @see #setZIndex(int) */\r
        public int getZIndex () {\r
-               Group parent = getParent();\r
+               Group parent = this.parent;\r
                if (parent == null) return -1;\r
                return parent.getChildren().indexOf(this, true);\r
        }\r
 \r
        /** Calls {@link #clipBegin(float, float, float, float)} to clip this actor's bounds. */\r
        public boolean clipBegin () {\r
-               return clipBegin(getX(), getY(), getWidth(), getHeight());\r
+               return clipBegin(x, y, width, height);\r
        }\r
 \r
        /** Clips the specified screen aligned rectangle, specified relative to the transform matrix of the stage's SpriteBatch. The\r
@@ -529,9 +563,9 @@ public class Actor {
                tableBounds.y = y;\r
                tableBounds.width = width;\r
                tableBounds.height = height;\r
-               Stage stage = getStage();\r
+               Stage stage = this.stage;\r
                Rectangle scissorBounds = Pools.obtain(Rectangle.class);\r
-               ScissorStack.calculateScissors(stage.getCamera(), stage.getSpriteBatch().getTransformMatrix(), tableBounds, scissorBounds);\r
+               stage.calculateScissors(tableBounds, scissorBounds);\r
                if (ScissorStack.pushScissors(scissorBounds)) return true;\r
                Pools.free(scissorBounds);\r
                return false;\r
@@ -544,7 +578,7 @@ public class Actor {
 \r
        /** Transforms the specified point in screen coordinates to the actor's local coordinate system. */\r
        public Vector2 screenToLocalCoordinates (Vector2 screenCoords) {\r
-               Stage stage = getStage();\r
+               Stage stage = this.stage;\r
                if (stage == null) return screenCoords;\r
                return stageToLocalCoordinates(stage.screenToStageCoordinates(screenCoords));\r
        }\r
@@ -557,36 +591,48 @@ public class Actor {
                return stageCoords;\r
        }\r
 \r
-       /** Transforms the specified point in the actor's coordinates to be in the stage's coordinates. Note this method will ONLY work\r
-        * for screen aligned, unrotated, unscaled actors! */\r
+       /** Transforms the specified point in the actor's coordinates to be in the stage's coordinates.\r
+        * @see Stage#toScreenCoordinates(Vector2, com.badlogic.gdx.math.Matrix4) */\r
        public Vector2 localToStageCoordinates (Vector2 localCoords) {\r
-               Actor actor = this;\r
-               while (actor != null) {\r
-                       if (actor.getRotation() != 0 || actor.getScaleX() != 1 || actor.getScaleY() != 1)\r
-                               throw new GdxRuntimeException("Only unrotated and unscaled actors may use this method.");\r
-                       localCoords.x += actor.getX();\r
-                       localCoords.y += actor.getY();\r
-                       actor = actor.getParent();\r
-               }\r
-               return localCoords;\r
+               return localToAscendantCoordinates(null, localCoords);\r
        }\r
 \r
-       /** Transforms the specified point in the actor's coordinates to be in the parent's coordinates. Note this method will ONLY work\r
-        * for screen aligned, unrotated, unscaled actors! */\r
+       /** Transforms the specified point in the actor's coordinates to be in the parent's coordinates. */\r
        public Vector2 localToParentCoordinates (Vector2 localCoords) {\r
-               if (getRotation() != 0 || getScaleX() != 1 || getScaleY() != 1)\r
-                       throw new GdxRuntimeException("Only unrotated and unscaled actors may use this method.");\r
-               localCoords.x += getX();\r
-               localCoords.y += getY();\r
+               final float rotation = -this.rotation;\r
+               final float scaleX = this.scaleX;\r
+               final float scaleY = this.scaleY;\r
+               final float x = this.x;\r
+               final float y = this.y;\r
+               if (rotation == 0) {\r
+                       if (scaleX == 1 && scaleY == 1) {\r
+                               localCoords.x += x;\r
+                               localCoords.y += y;\r
+                       } else {\r
+                               final float originX = this.originX;\r
+                               final float originY = this.originY;\r
+                               localCoords.x = (localCoords.x - originX) * scaleX + originX + x;\r
+                               localCoords.y = (localCoords.y - originY) * scaleY + originY + y;\r
+                       }\r
+               } else {\r
+                       final float cos = (float)Math.cos(rotation * MathUtils.degreesToRadians);\r
+                       final float sin = (float)Math.sin(rotation * MathUtils.degreesToRadians);\r
+                       final float originX = this.originX;\r
+                       final float originY = this.originY;\r
+                       final float tox = localCoords.x - originX;\r
+                       final float toy = localCoords.y - originY;\r
+                       localCoords.x = (tox * cos + toy * sin) * scaleX + originX + x;\r
+                       localCoords.y = (tox * -sin + toy * cos) * scaleY + originY + y;\r
+               }\r
                return localCoords;\r
        }\r
 \r
        /** Converts coordinates for this actor to those of a parent actor. The ascendant does not need to be a direct parent. */\r
        public Vector2 localToAscendantCoordinates (Actor ascendant, Vector2 localCoords) {\r
                Actor actor = this;\r
-               while (actor.getParent() != null) {\r
+               while (actor.parent != null) {\r
                        actor.localToParentCoordinates(localCoords);\r
-                       actor = actor.getParent();\r
+                       actor = actor.parent;\r
                        if (actor == ascendant) break;\r
                }\r
                return localCoords;\r
@@ -594,79 +640,30 @@ public class Actor {
 \r
        /** Converts the coordinates given in the parent's coordinate system to this actor's coordinate system. */\r
        public Vector2 parentToLocalCoordinates (Vector2 parentCoords) {\r
-               final float rotation = getRotation();\r
-               final float scaleX = getScaleX();\r
-               final float scaleY = getScaleY();\r
-               final float childX = getX();\r
-               final float childY = getY();\r
-\r
+               final float rotation = this.rotation;\r
+               final float scaleX = this.scaleX;\r
+               final float scaleY = this.scaleY;\r
+               final float childX = x;\r
+               final float childY = y;\r
                if (rotation == 0) {\r
                        if (scaleX == 1 && scaleY == 1) {\r
                                parentCoords.x -= childX;\r
                                parentCoords.y -= childY;\r
                        } else {\r
-                               final float originX = getOriginX();\r
-                               final float originY = getOriginY();\r
-                               if (originX == 0 && originY == 0) {\r
-                                       parentCoords.x = (parentCoords.x - childX) / scaleX;\r
-                                       parentCoords.y = (parentCoords.y - childY) / scaleY;\r
-                               } else {\r
-                                       parentCoords.x = (parentCoords.x - childX - originX) / scaleX + originX;\r
-                                       parentCoords.y = (parentCoords.y - childY - originY) / scaleY + originY;\r
-                               }\r
+                               final float originX = this.originX;\r
+                               final float originY = this.originY;\r
+                               parentCoords.x = (parentCoords.x - childX - originX) / scaleX + originX;\r
+                               parentCoords.y = (parentCoords.y - childY - originY) / scaleY + originY;\r
                        }\r
                } else {\r
                        final float cos = (float)Math.cos(rotation * MathUtils.degreesToRadians);\r
                        final float sin = (float)Math.sin(rotation * MathUtils.degreesToRadians);\r
-\r
-                       final float originX = getOriginX();\r
-                       final float originY = getOriginY();\r
-\r
-                       if (scaleX == 1 && scaleY == 1) {\r
-                               if (originX == 0 && originY == 0) {\r
-                                       float tox = parentCoords.x - childX;\r
-                                       float toy = parentCoords.y - childY;\r
-\r
-                                       parentCoords.x = tox * cos + toy * sin;\r
-                                       parentCoords.y = tox * -sin + toy * cos;\r
-                               } else {\r
-                                       final float worldOriginX = childX + originX;\r
-                                       final float worldOriginY = childY + originY;\r
-                                       final float fx = -originX;\r
-                                       final float fy = -originY;\r
-\r
-                                       final float x1 = cos * fx - sin * fy + worldOriginX;\r
-                                       final float y1 = sin * fx + cos * fy + worldOriginY;\r
-\r
-                                       final float tox = parentCoords.x - x1;\r
-                                       final float toy = parentCoords.y - y1;\r
-\r
-                                       parentCoords.x = tox * cos + toy * sin;\r
-                                       parentCoords.y = tox * -sin + toy * cos;\r
-                               }\r
-                       } else {\r
-                               if (originX == 0 && originY == 0) {\r
-                                       final float tox = parentCoords.x - childX;\r
-                                       final float toy = parentCoords.y - childY;\r
-\r
-                                       parentCoords.x = (tox * cos + toy * sin) / scaleX;\r
-                                       parentCoords.y = (tox * -sin + toy * cos) / scaleY;\r
-                               } else {\r
-                                       final float worldOriginX = childX + originX;\r
-                                       final float worldOriginY = childY + originY;\r
-                                       final float fx = -originX * scaleX;\r
-                                       final float fy = -originY * scaleY;\r
-\r
-                                       final float x1 = cos * fx - sin * fy + worldOriginX;\r
-                                       final float y1 = sin * fx + cos * fy + worldOriginY;\r
-\r
-                                       final float tox = parentCoords.x - x1;\r
-                                       final float toy = parentCoords.y - y1;\r
-\r
-                                       parentCoords.x = (tox * cos + toy * sin) / scaleX;\r
-                                       parentCoords.y = (tox * -sin + toy * cos) / scaleY;\r
-                               }\r
-                       }\r
+                       final float originX = this.originX;\r
+                       final float originY = this.originY;\r
+                       final float tox = parentCoords.x - childX - originX;\r
+                       final float toy = parentCoords.y - childY - originY;\r
+                       parentCoords.x = (tox * cos + toy * sin) / scaleX + originX;\r
+                       parentCoords.y = (tox * -sin + toy * cos) / scaleY + originY;\r
                }\r
                return parentCoords;\r
        }\r
@@ -678,6 +675,6 @@ public class Actor {
                        int dotIndex = name.lastIndexOf('.');\r
                        if (dotIndex != -1) name = name.substring(dotIndex + 1);\r
                }\r
-               return name + " " + x + "," + y + " " + width + "x" + height;\r
+               return name;\r
        }\r
 }\r