Package com.badlogic.gdx.scenes.scene2d

Source Code of com.badlogic.gdx.scenes.scene2d.Stage

/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

package com.badlogic.gdx.scenes.scene2d;

import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Disposable;

/** <p>
* A Stage is a container for {@link Actor}s and handles distributing touch events, animating Actors and asking them to render
* themselves. A Stage is basically a 2D scenegraph with hierarchies of Actors.
* </p>
*
* <p>
* A Stage object fills the whole screen. It has a width and height given in device independent pixels. It will create a
* {@link Camera} that maps this viewport to the given real screen resolution. If the stretched attribute is set to true then the
* viewport is enforced no matter the difference in aspect ratio between the stage object and the screen dimensions. In case
* stretch is disabled then the viewport is extended in the bigger screen dimensions.
* </p>
*
* <p>
* Actors have a z-order which is equal to the order they were inserted into this Stage. Actors inserted later will be drawn on
* top of Actors added earlier. Touch events that will get distributed to later Actors first.
* </p>
*
* <p>
* Actors can get focused. When your game pauses and resumes make sure to call the {@link Stage#unfocusAll()} method so that the
* focus states get reset for each pointer id. You also have to make sure that the Actors that were focused reset their state if
* the depend on being focused, e.g. wait for a touch up event. An easier way to tackle this is to recreate the Stage if possible.
* </p>
*
* @author mzechner */
public class Stage extends InputAdapter implements Disposable {
  protected float width;
  protected float height;
  protected float centerX;
  protected float centerY;
  protected boolean stretch;

  protected final Group root;

  protected final SpriteBatch batch;
  protected Camera camera;

  /** <p>
   * Constructs a new Stage object with the given dimensions. If the device resolution does not equal the Stage objects
   * dimensions the stage object will setup a projection matrix to guarantee a fixed coordinate system. If stretch is disabled
   * then the bigger dimension of the Stage will be increased to accomodate the actual device resolution.
   * </p>
   *
   * @param width the width of the viewport
   * @param height the height of the viewport
   * @param stretch whether to stretch the viewport to the real device resolution */
  public Stage (float width, float height, boolean stretch) {
    this.width = width;
    this.height = height;
    this.stretch = stretch;
    this.root = new Group("root");
    this.batch = new SpriteBatch();
    this.camera = new OrthographicCamera();
    setViewport(width, height, stretch);
  }

  /** Sets the viewport dimensions in device independent pixels. If stretch is false and the viewport aspect ratio is not equal to
   * the device ratio then the bigger dimension of the viewport will be extended (device independent pixels stay quardatic
   * instead of getting stretched).
   *
   * @param width thew width of the viewport in device independent pixels
   * @param height the height of the viewport in device independent pixels
   * @param stretch whether to stretch the viewport or not */
  public void setViewport (float width, float height, boolean stretch) {
    if (!stretch) {
      if (width > height && width / (float)Gdx.graphics.getWidth() <= height / (float)Gdx.graphics.getHeight()) {
        float toDeviceSpace = Gdx.graphics.getHeight() / height;
        float toViewportSpace = height / Gdx.graphics.getHeight();

        float deviceWidth = width * toDeviceSpace;
        this.width = width + (Gdx.graphics.getWidth() - deviceWidth) * toViewportSpace;
        this.height = height;
      } else {
        float toDeviceSpace = Gdx.graphics.getWidth() / width;
        float toViewportSpace = width / Gdx.graphics.getWidth();

        float deviceHeight = height * toDeviceSpace;
        this.height = height + (Gdx.graphics.getHeight() - deviceHeight) * toViewportSpace;
        this.width = width;
      }
    } else {
      this.width = width;
      this.height = height;
    }

    this.stretch = stretch;
    centerX = this.width / 2;
    centerY = this.height / 2;

    camera.position.set(centerX, centerY, 0);
    camera.viewportWidth = this.width;
    camera.viewportHeight = this.height;
  }

  /** 8
   * @return the width of the stage in dips */
  public float width () {
    return width;
  }

  /** @return the height of the stage in dips */
  public float height () {
    return height;
  }

  /** @return the x-coordinate of the left edge of the stage in dips */
  public int left () {
    return 0;
  }

  /** @return the x-coordinate of the right edge of the stage in dips */
  public float right () {
    return width - 1;
  }

  /** @return the y-coordinate of the top edge of the stage in dips */
  public float top () {
    return height - 1;
  }

  /** @return the y-coordinate of the bottom edge of the stage in dips */
  public float bottom () {
    return 0;
  }

  /** @return the center x-coordinate of the stage in dips */
  public float centerX () {
    return centerX;
  }

  /** @return the center y-coordinate of the stage in dips */
  public float centerY () {
    return centerY;
  }

  /** @return whether the stage is stretched */
  public boolean isStretched () {
    return stretch;
  }

  /** Finds the {@link Actor} with the given name in the stage hierarchy.
   * @param name
   * @return the Actor or null if it couldn't be found. */
  public Actor findActor (String name) {
    return root.findActor(name);
  }

  /** @return all top level {@link Actor}s */
  public List<Actor> getActors () {
    return root.getActors();
  }

  /** @return all top level {@link Group}s */
  public List<Group> getGroups () {
    return root.getGroups();
  }

  final Vector2 point = new Vector2();
  final Vector2 coords = new Vector2();

  /** Call this to distribute a touch down event to the stage.
   * @param x the x coordinate of the touch in screen coordinates
   * @param y the y coordinate of the touch in screen coordinates
   * @param pointer the pointer index
   * @param button the button that's been pressed
   * @return whether an {@link Actor} in the scene processed the event or not */
  @Override
  public boolean touchDown (int x, int y, int pointer, int button) {
    toStageCoordinates(x, y, coords);
    Group.toChildCoordinates(root, coords.x, coords.y, point);
    return root.touchDown(point.x, point.y, pointer);
  }

  /** Call this to distribute a touch Up event to the stage.
   *
   * @param x the x coordinate of the touch in screen coordinates
   * @param y the y coordinate of the touch in screen coordinates
   * @param pointer the pointer index
   * @return whether an {@link Actor} in the scene processed the event or not */
  @Override
  public boolean touchUp (int x, int y, int pointer, int button) {
    Actor actor = root.focusedActor[pointer];
    if (actor == null) return false;
    toStageCoordinates(x, y, coords);
    Group.toChildCoordinates(root, coords.x, coords.y, point);
    root.touchUp(point.x, point.y, pointer);
    return true;
  }

  /** Call this to distribute a touch dragged event to the stage.
   * @param x the x coordinate of the touch in screen coordinates
   * @param y the y coordinate of the touch in screen coordinates
   * @param pointer the pointer index
   * @return whether an {@link Actor} in the scene processed the event or not */
  @Override
  public boolean touchDragged (int x, int y, int pointer) {
    boolean foundFocusedActor = false;
    for (int i = 0, n = root.focusedActor.length; i < n; i++) {
      if (root.focusedActor[i] != null) {
        foundFocusedActor = true;
        break;
      }
    }
    if (!foundFocusedActor) return false;
    toStageCoordinates(x, y, coords);
    Group.toChildCoordinates(root, coords.x, coords.y, point);
    root.touchDragged(point.x, point.y, pointer);
    return true;
  }

  /** Call this to distribute a touch moved event to the stage. This event will only ever appear on the desktop.
   * @param x the x coordinate of the touch in screen coordinates
   * @param y the y coordinate of the touch in screen coordinates
   * @return whether an {@link Actor} in the scene processed the event or not */
  @Override
  public boolean touchMoved (int x, int y) {
    toStageCoordinates(x, y, coords);
    Group.toChildCoordinates(root, coords.x, coords.y, point);
    return root.touchMoved(point.x, point.y);
  }

  /** Call this to distribute a mouse scroll event to the stage. This event will only ever appear on the desktop.
   * @param amount the scroll amount.
   * @return whether an {@link Actor} in the scene processed the event or not. */
  @Override
  public boolean scrolled (int amount) {
    return root.scrolled(amount);
  }

  /** Called when a key was pressed
   *
   * @param keycode one of the constants in {@link Keys}
   * @return whether the input was processed */
  @Override
  public boolean keyDown (int keycode) {
    return root.keyDown(keycode);
  }

  /** Called when a key was released
   *
   * @param keycode one of the constants in {@link Keys}
   * @return whether the input was processed */
  @Override
  public boolean keyUp (int keycode) {
    return root.keyUp(keycode);
  }

  /** Called when a key was typed
   *
   * @param character The character
   * @return whether the input was processed */
  @Override
  public boolean keyTyped (char character) {
    return root.keyTyped(character);
  }

  /** Calls the {@link Actor#act(float)} method of all contained Actors. This will advance any {@link Action}s active for an
   * Actor.
   * @param delta the delta time in seconds since the last invocation */
  public void act (float delta) {
    root.act(delta);
  }

  /** Renders the stage */
  public void draw () {
    camera.update();
    batch.setProjectionMatrix(camera.combined);
    batch.begin();
    root.draw(batch, 1);
    batch.end();
  }

  /** Disposes the stage */
  public void dispose () {
    batch.dispose();
  }

  /** Adds an {@link Actor} to this stage
   * @param actor the Actor */
  public void addActor (Actor actor) {
    root.addActor(actor);
  }

  /** @return the Stage graph as a silly string */
  public String graphToString () {
    StringBuilder buffer = new StringBuilder();
    graphToString(buffer, root, 0);
    return buffer.toString();
  }

  private void graphToString (StringBuilder buffer, Actor actor, int level) {
    for (int i = 0; i < level; i++)
      buffer.append(' ');

    buffer.append(actor);
    buffer.append("\n");

    if (actor instanceof Group) {
      Group group = (Group)actor;
      for (int i = 0; i < group.getActors().size(); i++)
        graphToString(buffer, group.getActors().get(i), level + 1);
    }
  }

  /** @return the root {@link Group} of this Stage. */
  public Group getRoot () {
    return root;
  }

  /** @return the {@link SpriteBatch} offers its {@link Actor}s for rendering. */
  public SpriteBatch getSpriteBatch () {
    return batch;
  }

  /** @return the {@link Camera} of this stage. */
  public Camera getCamera () {
    return camera;
  }

  /** Sets the {@link Camera} this stage uses. You are responsible for setting it up properly! The {@link Stage#draw()} will call
   * the Camera's update() method and use it's combined matrix as the projection matrix for the SpriteBatch.
   * @param camera the {@link Camera} */
  public void setCamera (Camera camera) {
    this.camera = camera;
  }

  /** @return the {@link Actor} last hit by a touch event. */
  public Actor getLastTouchedChild () {
    return root.lastTouchedChild;
  }

  /** Returns the {@link Actor} intersecting with the point (x,y) in stage coordinates. Hit testing is performed in the order the
   * Actors were inserted into the Stage, last inserted Actors being tested first. To get stage coordinates from screen
   * coordinates use {@link #toStageCoordinates(int, int, Vector2)}.
   *
   * @param x the x-coordinate in stage coordinates
   * @param y the y-coordinate in stage coordinates
   * @return the hit Actor or null */
  public Actor hit (float x, float y) {
    Group.toChildCoordinates(root, x, y, point);
    return root.hit(point.x, point.y);
  }

  final Vector3 tmp = new Vector3();

  /** Transforms the given screen coordinates to stage coordinates
   * @param x the x-coordinate in screen coordinates
   * @param y the y-coordinate in screen coordinates
   * @param out the output {@link Vector2}. */
  public void toStageCoordinates (int x, int y, Vector2 out) {
    camera.unproject(tmp.set(x, y, 0));
    out.x = tmp.x;
    out.y = tmp.y;
  }

  /** Clears this stage, removing all {@link Actor}s and {@link Group}s. */
  public void clear () {
    root.clear();
  }

  /** Removes the given {@link Actor} from the stage by trying to find it recursively in the scenegraph.
   * @param actor the actor */
  public void removeActor (Actor actor) {
    root.removeActorRecursive(actor);
  }

  /** Unfocues all {@link Actor} instance currently focused. You should call this in case your app resumes to clear up any pressed
   * states. Make sure the Actors forget their states as well! */
  public void unfocusAll () {
    root.unfocusAll();
  }
}
TOP

Related Classes of com.badlogic.gdx.scenes.scene2d.Stage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.