Package com.badlogic.gdx.scenes.scene2d.ui

Source Code of com.badlogic.gdx.scenes.scene2d.ui.Touchpad

/*******************************************************************************
* 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.ui;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Pools;

/** An on-screen joystick. The movement area of the joystick is circular, centered on the touchpad, and its size determined by the
* smaller touchpad dimension.
* <p>
* The preferred size of the touchpad is determined by the background.
* <p>
* {@link ChangeEvent} is fired when the touchpad knob is moved. Cancelling the event will move the knob to where it was
* previously.
* @author Josh Street */
public class Touchpad extends Widget {
  private TouchpadStyle style;
  boolean touched;
  private float deadzoneRadius;
  private final Circle knobBounds = new Circle(0, 0, 0);
  private final Circle touchBounds = new Circle(0, 0, 0);
  private final Circle deadzoneBounds = new Circle(0, 0, 0);
  private final Vector2 knobPosition = new Vector2();
  private final Vector2 knobPercent = new Vector2();

  /** @param deadzoneRadius The distance in pixels from the center of the touchpad required for the knob to be moved. */
  public Touchpad (float deadzoneRadius, Skin skin) {
    this(deadzoneRadius, skin.get(TouchpadStyle.class));
  }

  /** @param deadzoneRadius The distance in pixels from the center of the touchpad required for the knob to be moved. */
  public Touchpad (float deadzoneRadius, Skin skin, String styleName) {
    this(deadzoneRadius, skin.get(styleName, TouchpadStyle.class));
  }

  /** @param deadzoneRadius The distance in pixels from the center of the touchpad required for the knob to be moved. */
  public Touchpad (float deadzoneRadius, TouchpadStyle style) {
    if (deadzoneRadius < 0) throw new IllegalArgumentException("deadzoneRadius must be > 0");
    this.deadzoneRadius = deadzoneRadius;

    knobPosition.set(getWidth() / 2f, getHeight() / 2f);

    setStyle(style);
    setWidth(getPrefWidth());
    setHeight(getPrefHeight());

    addListener(new InputListener() {
      @Override
      public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
        if (touched) return false;
        touched = true;
        calculatePositionAndValue(x, y, false);
        return true;
      }

      @Override
      public void touchDragged (InputEvent event, float x, float y, int pointer) {
        calculatePositionAndValue(x, y, false);
      }

      @Override
      public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
        touched = false;
        calculatePositionAndValue(x, y, true);
      }
    });
  }

  void calculatePositionAndValue (float x, float y, boolean isTouchUp) {
    float oldPositionX = knobPosition.x;
    float oldPositionY = knobPosition.y;
    float oldPercentX = knobPercent.x;
    float oldPercentY = knobPercent.y;
    float centerX = knobBounds.x;
    float centerY = knobBounds.y;
    knobPosition.set(centerX, centerY);
    knobPercent.set(0f, 0f);
    if (!isTouchUp) {
      if (!deadzoneBounds.contains(x, y)) {
        knobPercent.set((x - centerX) / knobBounds.radius, (y - centerY) / knobBounds.radius);
        float length = knobPercent.len();
        if (length > 1) knobPercent.scl(1 / length);
        if (knobBounds.contains(x, y)) {
          knobPosition.set(x, y);
        } else {
          knobPosition.set(knobPercent).nor().scl(knobBounds.radius).add(knobBounds.x, knobBounds.y);
        }
      }
    }
    if (oldPercentX != knobPercent.x || oldPercentY != knobPercent.y) {
      ChangeEvent changeEvent = Pools.obtain(ChangeEvent.class);
      if (fire(changeEvent)) {
        knobPercent.set(oldPercentX, oldPercentY);
        knobPosition.set(oldPositionX, oldPositionY);
      }
      Pools.free(changeEvent);
    }
  }

  public void setStyle (TouchpadStyle style) {
    if (style == null) throw new IllegalArgumentException("style cannot be null");
    this.style = style;
    invalidateHierarchy();
  }

  /** Returns the touchpad's style. Modifying the returned style may not have an effect until {@link #setStyle(TouchpadStyle)} is
   * called. */
  public TouchpadStyle getStyle () {
    return style;
  }

  @Override
  public Actor hit (float x, float y, boolean touchable) {
    return touchBounds.contains(x, y) ? this : null;
  }

  @Override
  public void layout () {
    // Recalc pad and deadzone bounds
    float halfWidth = getWidth() / 2;
    float halfHeight = getHeight() / 2;
    float radius = Math.min(halfWidth, halfHeight);
    touchBounds.set(halfWidth, halfHeight, radius);
    if (style.knob != null) radius -= Math.max(style.knob.getMinWidth(), style.knob.getMinHeight()) / 2;
    knobBounds.set(halfWidth, halfHeight, radius);
    deadzoneBounds.set(halfWidth, halfHeight, deadzoneRadius);
    // Recalc pad values and knob position
    knobPosition.set(halfWidth, halfHeight);
    knobPercent.set(0, 0);
  }

  @Override
  public void draw (SpriteBatch batch, float parentAlpha) {
    validate();

    Color c = getColor();
    batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);

    float x = getX();
    float y = getY();
    float w = getWidth();
    float h = getHeight();

    final Drawable bg = style.background;
    if (bg != null) bg.draw(batch, x, y, w, h);

    final Drawable knob = style.knob;
    if (knob != null) {
      x += knobPosition.x - knob.getMinWidth() / 2f;
      y += knobPosition.y - knob.getMinHeight() / 2f;
      knob.draw(batch, x, y, knob.getMinWidth(), knob.getMinHeight());
    }
  }

  @Override
  public float getPrefWidth () {
    return style.background != null ? style.background.getMinWidth() : 0;
  }

  @Override
  public float getPrefHeight () {
    return style.background != null ? style.background.getMinHeight() : 0;
  }

  public boolean isTouched () {
    return touched;
  }

  /** @param deadzoneRadius The distance in pixels from the center of the touchpad required for the knob to be moved. */
  public void setDeadzone (float deadzoneRadius) {
    if (deadzoneRadius < 0) throw new IllegalArgumentException("deadzoneRadius must be > 0");
    this.deadzoneRadius = deadzoneRadius;
    invalidate();
  }

  /** Returns the x-position of the knob relative to the center of the widget. The positive direction is right. */
  public float getKnobX () {
    return knobPosition.x;
  }

  /** Returns the y-position of the knob relative to the center of the widget. The positive direction is up. */
  public float getKnobY () {
    return knobPosition.y;
  }

  /** Returns the x-position of the knob as a percentage from the center of the touchpad to the edge of the circular movement
   * area. The positive direction is right. */
  public float getKnobPercentX () {
    return knobPercent.x;
  }

  /** Returns the y-position of the knob as a percentage from the center of the touchpad to the edge of the circular movement
   * area. The positive direction is up. */
  public float getKnobPercentY () {
    return knobPercent.y;
  }

  /** The style for a {@link Touchpad}.
   * @author Josh Street */
  public static class TouchpadStyle {
    /** Stretched in both directions. Optional. */
    public Drawable background;

    /** Optional. */
    public Drawable knob;

    public TouchpadStyle () {
    }

    public TouchpadStyle (Drawable background, Drawable knob) {
      this.background = background;
      this.knob = knob;
    }

    public TouchpadStyle (TouchpadStyle style) {
      this.background = style.background;
      this.knob = style.knob;
    }
  }
}
TOP

Related Classes of com.badlogic.gdx.scenes.scene2d.ui.Touchpad

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.