All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.flixel.ui.FlxAnalog Maven / Gradle / Ivy

The newest version!
package org.flixel.ui;

import org.flixel.FlxG;
import org.flixel.FlxGroup;
import org.flixel.FlxPoint;
import org.flixel.FlxSprite;
import org.flixel.FlxU;
import org.flixel.event.IFlxAnalog;

import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;

/**
 * An analog stick or thumbstick with callbacks. It can easily be customized by
 * overriding the parent methods.
 * 
 * @author Ka Wing Chin
 */
public class FlxAnalog extends FlxGroup
{
	/**
	 * Base image
	 */
	private final String ImgBase = "org/flixel/data/pack:base";
	/**
	 * Stick image
	 */
	private final String ImgThumb = "org/flixel/data/pack:stick";

	/**
	 * From radians to degrees.
	 */
	private final float DEGREES = (float) (180f / Math.PI);

	/**
	 * Used with public variable status, means not highlighted or
	 * pressed.
	 */
	public static final int NORMAL = 0;
	/**
	 * Used with public variable status, means highlighted (usually
	 * from mouse over).
	 */
	public static final int HIGHLIGHT = 1;
	/**
	 * Used with public variable status, means pressed (usually
	 * from mouse click).
	 */
	public static final int PRESSED = 2;
	/**
	 * Shows the current state of the button.
	 */
	public int status;

	/**
	 * X position of the upper left corner of this object in world space.
	 */
	public float x;
	/**
	 * Y position of the upper left corner of this object in world space.
	 */
	public float y;

	/**
	 * An list of analogs that are currently active.
	 */
	private static Array _analogs;
	/**
	 * This is just a pre-allocated x-y point container to be used however you
	 * like.
	 */
	protected FlxPoint _point;
	/**
	 * This function is called when the button is released.
	 */
	public IFlxAnalog onUp;
	/**
	 * This function is called when the button is pressed down.
	 */
	public IFlxAnalog onDown;
	/**
	 * This function is called when the mouse goes over the button.
	 */
	public IFlxAnalog onOver;
	/**
	 * This function is called when the button is hold down.
	 */
	public IFlxAnalog onPressed;

	/**
	 * The area which the joystick will react.
	 */
	private Circle _zone;
	/**
	 * The background of the joystick, also known as the base.
	 */
	public FlxSprite bg;
	/**
	 * The thumb
	 */
	public FlxSprite thumb;

	/**
	 * The radius where the thumb can move.
	 */
	private float _radius;
	private float _direction;
	private float _amount;

	/**
	 * The area which the touch is allowed to drag.
	 */
	private Circle _dragZone;
	/**
	 * The radius where the touch can move while dragging the thumb.
	 */
	private float _dragRadius;

	/**
	 * How fast the speed of this object is changing.
	 */
	public FlxPoint acceleration;
	/**
	 * The speed of easing when the thumb is released.
	 */
	private float _ease;
	/**
	 * Internal
	 */
	private float dx;
	private float dy;
	private double dist;

	/**
	 * Creates a new FlxAnalog object.
	 * 
	 * @param X The X-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param Y The Y-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param radius The radius where the thumb can move. Default 0, the
	 *        background will be used as radius.
	 * @param dragRadius The radius where the thumb can move. Default 0, the
	 *        background * 1.25 will be used as radius.
	 * @param ease The duration of the easing. The value must be between 0 and
	 *        1.
	 */
	public FlxAnalog(float x, float y, float radius, float dragRadius, float ease)
	{
		this.x = x;
		this.y = y;
		_radius = radius;
		_dragRadius = dragRadius;
		_ease = ease;

		if(_analogs == null)
			_analogs = new Array();
		_analogs.add(this);

		status = NORMAL;
		_direction = 0;
		_amount = 0;
		acceleration = new FlxPoint();
		_point = new FlxPoint();

		createBase();
		createThumb();
		createZone();
		createDragZone();
	}

	/**
	 * Creates a new FlxAnalog object.
	 * 
	 * @param X The X-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param Y The Y-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param radius The radius where the thumb can move. If 0, the background
	 *        will be used as radius.
	 * @param dragRadius The radius where the pointer can move while dragging
	 *        the thumb.
	 */
	public FlxAnalog(float x, float y, float radius, float dragRadius)
	{
		this(x, y, radius, dragRadius, .25f);
	}

	/**
	 * Creates a new FlxAnalog object.
	 * 
	 * @param X The X-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param Y The Y-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param radius The radius where the thumb can move. Default 0, the
	 *        background will be used as radius.
	 */
	public FlxAnalog(float x, float y, float radius)
	{
		this(x, y, radius, 0, .25f);
	}

	/**
	 * Creates a new FlxAnalog object.
	 * 
	 * @param X The X-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 * @param Y The Y-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 */
	public FlxAnalog(float x, float y)
	{
		this(x, y, 0, 0, .25f);
	}

	/**
	 * Creates a new FlxAnalog object.
	 * 
	 * @param X The X-coordinate of the point in space. The position doesn't
	 *        start at top-left, but the center of the thumb.
	 */
	public FlxAnalog(float x)
	{
		this(x, 0, 0, 0, .25f);
	}

	/**
	 * Creates a new FlxAnalog object.
	 */
	public FlxAnalog()
	{
		this(0, 0, 0, 0, .25f);
	}

	/**
	 * Creates the background of the analog stick. Override this to customize
	 * the background.
	 */
	protected void createBase()
	{
		bg = new FlxSprite(x, y).loadGraphic(ImgBase);
		bg.x += -bg.width * .5f;
		bg.y += -bg.height * .5f;
		bg.scrollFactor.x = bg.scrollFactor.y = 0;
		bg.setSolid(false);
		bg.ignoreDrawDebug = true;
		add(bg);
	}

	/**
	 * Creates the thumb of the analog stick. Override this to customize the
	 * thumb.
	 */
	protected void createThumb()
	{
		thumb = new FlxSprite(x, y).loadGraphic(ImgThumb);
		thumb.scrollFactor.x = thumb.scrollFactor.y = 0;
		thumb.setSolid(false);
		thumb.ignoreDrawDebug = true;
		add(thumb);
	}

	/**
	 * Creates the touch zone. It's based on the size of the background. The
	 * thumb will react when the mouse is in the zone. Override this to
	 * customize the zone.
	 */
	protected void createZone()
	{
		if(_radius == 0)
			_radius = bg.width * .5f;
		_zone = new Circle(x, y, _radius);
	}

	/**
	 * Creates the move zone. The thumb can only move in this zone. It's based
	 * on the size of the background * 1.25. When the mouse is out the zone, the
	 * thumb will be released. Override this to customize the drag zone.
	 */
	protected void createDragZone()
	{
		if(_dragRadius == 0)
			_dragRadius = bg.width * 1.25f;
		_dragZone = new Circle(x, y, _dragRadius);
	}

	/**
	 * Clean up memory.
	 */
	@Override
	public void destroy()
	{
		super.destroy();
		if(_analogs != null)
			_analogs.clear();
		_analogs = null;
		onUp = onDown = onOver = onPressed = null;
		acceleration = null;
		_point = null;
		thumb = null;
		_zone = null;
		_dragZone = null;
		bg = null;
		thumb = null;
	}

	/**
	 * Update the behavior.
	 */
	@Override
	public void update()
	{
		boolean offAll = true;
		int pointerId = 0;
		int totalPointers = FlxG.mouse.activePointers + 1;

		while(pointerId < totalPointers)
		{
			if(!updateAnalog(pointerId))
			{
				offAll = false;
				break;
			}
			++pointerId;
		}

		thumb.x = (float) (x + MathUtils.cos(_direction) * _amount * _radius - (thumb.width * .5f));
		thumb.y = (float) (y + MathUtils.sin(_direction) * _amount * _radius - (thumb.height * .5f));

		if(offAll)
			status = NORMAL;

		super.update();
	}

	protected boolean updateAnalog(int pointerId)
	{
		boolean offAll = true;
		FlxG.mouse.getScreenPosition(pointerId, FlxG.camera, _point);

		if(_zone.contains(_point.x, _point.y) || (_dragZone.contains(_point.x, _point.y) && status == PRESSED))
		{
			offAll = false;
			if(FlxG.mouse.pressed(pointerId))
			{
				status = PRESSED;
				if(FlxG.mouse.justPressed(pointerId))
				{
					if(onDown != null)
						onDown.callback();
				}

				if(status == PRESSED)
				{
					if(onPressed != null)
						onPressed.callback();

					dx = _point.x - x;
					dy = _point.y - y;

					dist = Math.sqrt(dx * dx + dy * dy);
					if(dist < 1)
						dist = 0;
					_direction = (float) MathUtils.atan2(dy, dx);
					_amount = FlxU.min(_radius, (float) dist) / _radius;

					acceleration.x = (float) (MathUtils.cos(_direction) * _amount * _radius);
					acceleration.y = (float) (MathUtils.sin(_direction) * _amount * _radius);
				}
			}
			else if(FlxG.mouse.justReleased(pointerId) && status == PRESSED)
			{
				status = HIGHLIGHT;
				if(onUp != null)
					onUp.callback();
				acceleration.x = 0;
				acceleration.y = 0;
			}

			if(status == NORMAL)
			{
				status = HIGHLIGHT;
				if(onOver != null)
					onOver.callback();
			}
		}
		if((status == HIGHLIGHT || status == NORMAL) && _amount != 0)
		{
			_amount *= _ease;
			if(Math.abs(_amount) < 0.1f)
				_amount = 0;
		}
		return offAll;
	}

	/**
	 * Returns the angle in degrees.
	 * 
	 * @return The angle.
	 */
	public float getAngle()
	{
		return (MathUtils.atan2(acceleration.y, acceleration.x) * DEGREES);
	}

	/**
	 * Set alpha to a number between 0 and 1 to change the opacity
	 * of the analog.
	 * 
	 * @param Alpha
	 */
	public void setAlpha(float Alpha)
	{
		for(int i = 0; i < members.size; i++)
		{
			((FlxSprite) members.get(i)).setAlpha(Alpha);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy