using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
namespace CarbonInput {
///
/// Touch control simulating a thumbstick.
///
public class TouchStick : BaseTouchInput, IPointerDownHandler, IPointerUpHandler, IDragHandler {
private const float NearZero = 0.0001f;
///
/// Horizontal axis of this control.
///
[Tooltip("Horizontal axis")]
public CAxis X = CAxis.LX;
///
/// Vertical axis of this control.
///
[Tooltip("Vertical axis")]
public CAxis Y = CAxis.LY;
///
/// Touches inside this area will be handled by the stick.
///
[Tooltip("Touches inside this area will be handled by the stick.")]
public RectTransform TouchArea;
///
/// Base of the joystick.
///
[Tooltip("Base of the joystick.")]
public RectTransform Base;
///
/// Knob of the joystick.
///
[Tooltip("Knob of the joystick.")]
public RectTransform Stick;
///
/// Maximum distance between center of base and center of stick.
///
[Tooltip("Maximum distance between center of base and center of stick.")]
[Range(20, 120)]
public float Range = 60;
///
/// Should the joystick disappear on release?
///
[Tooltip("Should the joystick disappear on release?")]
public bool HideOnRelease;
///
/// If HideOnRelease is set to true, this value will determine after which time the joystick will start to fade out.
///
[Tooltip("If HideOnRelease is set to true, this value will determine after which time the joystick will start to fade out.")]
public float FadeoutDelay;
///
/// If HideOnRelease is set to true, this value will determine how long the fadeout will last.
///
[Tooltip("If HideOnRelease is set to true, this value will determine how long the fadeout will last.")]
public float FadeoutTime = 1f;
///
/// If the user moves to far away from the stick, should the stick follow?
///
[Tooltip("If the user moves to far away from the stick, should the stick follow?")]
public bool Movable;
private CanvasRenderer[] childRenderer;
void Start() {
InitMapping();
childRenderer = GetComponentsInChildren();
if(HideOnRelease) Hide(false);
}
///
/// Shows this control.
///
public void Show() {
StopAllCoroutines();
SetOpacity(1f);
}
///
/// Hides this control.
///
/// If true, the control will slowly fade out.
public void Hide(bool fadeout) {
StopAllCoroutines();
if(fadeout) StartCoroutine(FadeSequence());
else SetOpacity(0f);
}
///
/// Sets the opacity of this control and all children.
///
///
private void SetOpacity(float opacity) {
foreach(CanvasRenderer renderer in childRenderer) renderer.SetAlpha(opacity);
}
///
/// Coroutine used to slowly fadeout.
///
///
private IEnumerator FadeSequence() {
if(FadeoutDelay > 0) yield return new WaitForSeconds(FadeoutDelay);
float opacity = 1f;
float speed = 1f / FadeoutTime;
while(opacity >= 0.0f) {
opacity -= Time.deltaTime * speed;
if(opacity < 0) opacity = 0;
SetOpacity(opacity);
yield return null;
}
}
///
/// Sets the value of this stick in the and also sets the knob position.
/// If is true, it will also follow the user.
///
/// Touch position in world space
private void UpdateStick(Vector2 pos) {
// get direction in local space
Vector2 direction = (pos - (Vector2)Base.position);
direction.x /= Base.lossyScale.x;
direction.y /= Base.lossyScale.y;
float length = direction.magnitude;
if(length < NearZero) {
UpdateAxis(Vector2.zero);
return;
}
if(length > Range) {
if(Movable) {
Vector2 delta = direction.normalized * (length - Range);
Vector2 newPos = (Vector2)Base.localPosition + delta;
newPos.x = Mathf.Clamp(newPos.x, TouchArea.rect.xMin, TouchArea.rect.xMax);
newPos.y = Mathf.Clamp(newPos.y, TouchArea.rect.yMin, TouchArea.rect.yMax);
Base.localPosition = newPos;
}
length = Range;
}
UpdateAxis(direction.normalized * (length / Range));
}
///
/// Updates the .
///
///
private void UpdateAxis(Vector2 axis) {
if(Mapping == null) return;
Stick.localPosition = axis * Range;
Mapping[X] = axis.x;
Mapping[Y] = -axis.y; // invert to match "normal" controller axis
}
public void OnPointerDown(PointerEventData data) {
Show();
if(RectTransformUtility.RectangleContainsScreenPoint(Stick, data.position) ||
RectTransformUtility.RectangleContainsScreenPoint(Base, data.position)) {
UpdateStick(data.position);
} else if(Movable) {
Base.position = data.position;
UpdateAxis(Vector2.zero);
}
}
public void OnPointerUp(PointerEventData data) {
UpdateAxis(Vector2.zero);
if(HideOnRelease) Hide(true);
}
public void OnDrag(PointerEventData data) {
UpdateStick(data.position);
}
}
}