Unity: EasyJoystick.cs

// EasyJoystick library is copyright (c) of Hedgehog Team
// Please send feedback or bug reports to the.hedgehog.team@gmail.com
using UnityEngine;
using System.Collections;

/// <summary>
/// Release notes:
/// EasyJoystick V2.2 Mai 2013
/// =============================
/// 	* Dynamic joystick no longer show when there are hover reserved area
/// 
/// EasyJoystick V2.1 Mai 2013
/// =============================
/// 	* Bugs fixed
/// 	------------
/// 	- The joystick touch wasn't been correct in some case
/// 
/// 
/// EasyJoystick V2.0 Avril 2013
/// ============================= 
///		* New
/// 	-----------------
/// 	- Add virtual screen to keep size position
/// 	- Add new joystick events : On_JoystickMoveStart, On_JoystickTouchStart, On_JoystickTap, On_JoystickDoubleTap,On_JoystickTouchUp
/// 	- Add new option to reset joystick position, when touch exit the joystick area
/// 	- Add the possibility to enable / disable joystick axis X or Y 
/// 	- Add new member isActivated to desactivated the joystick, but it always show on the screen
/// 	- Add new member to clamp rotation in direct mode when you're in localrotation
/// 	- Add new member to do an auto stabilisation in direct mode when you're in localrotation
/// 	- Add show dynamic joystick in edit mode
/// 	- Some optimisations
/// 	- Add new method Axis2Angle to MovingJoystick class that allow to return the joystick angle direction between -170 to 170
/// 	- Add option to show real area use by the joystick texture
/// 	- Add UseGuiLayout option
/// 	- Add Gui depth parameter
/// 
/// 	* Bugs fixed
/// 	------------
/// 	- Gravity is now always apply correctly
/// 	- Dead zone is correctly take into account
/// 	- the event JoystickMoveEnd don't send any more at startup
/// 
/// V1.0 November 2012
/// =============================
/// 	- First release

/// <summary>
/// This is the main class of EasyJoystick engine. 
/// 
/// For add joystick to your scene, use the menu Hedgehog Team<br>
/// </summary>
[ExecuteInEditMode]
public class EasyJoystick : MonoBehaviour
{
	
	#region Delegate
		public delegate void JoystickMoveStartHandler (MovingJoystick move);

		public delegate void JoystickMoveHandler (MovingJoystick move);

		public delegate void JoystickMoveEndHandler (MovingJoystick move);

		public delegate void JoystickTouchStartHandler (MovingJoystick move);

		public delegate void JoystickTapHandler (MovingJoystick move);

		public delegate void JoystickDoubleTapHandler (MovingJoystick move);

		public delegate void JoystickTouchUpHandler (MovingJoystick move);
	#endregion
	
	#region Event
		/// <summary>
		/// Occurs the joystick starts move.
		/// </summary>
		public static event JoystickMoveStartHandler On_JoystickMoveStart;
		/// <summary>
		/// Occurs when the joystick move.
		/// </summary>
		public static event JoystickMoveHandler On_JoystickMove;
		/// <summary>
		/// Occurs when the joystick stops move
		/// </summary>
		public static event JoystickMoveEndHandler On_JoystickMoveEnd;
		/// <summary>
		/// Occurs when a touch start hover the joystick
		/// </summary>
		public static event JoystickTouchStartHandler On_JoystickTouchStart;
		/// <summary>
		/// Occurs when a tap happen's on the joystick
		/// </summary>
		public static event JoystickTapHandler On_JoystickTap;
		/// <summary>
		/// Occurs when a double tap happen's on the joystick
		/// </summary>
		public static event JoystickDoubleTapHandler On_JoystickDoubleTap;
		/// <summary>
		/// Occurs when touch up happen's on the joystick
		/// </summary>
		public static event JoystickTouchUpHandler On_JoystickTouchUp;
	#endregion
	
	#region Enumeration
		/// <summary>
		/// Joystick anchor.
		/// </summary>
		public enum JoystickAnchor
		{
				None,
				UpperLeft,
				UpperCenter,
				UpperRight,
				MiddleLeft,
				MiddleCenter,
				MiddleRight,
				LowerLeft,
				LowerCenter,
				LowerRight}
		;
		/// <summary>
		/// Properties influenced by the joystick
		/// </summary>
		public enum PropertiesInfluenced
		{
				Rotate,
				RotateLocal,
				Translate,
				TranslateLocal,
				Scale
		}
		/// <summary>
		/// Axis influenced by the joystick
		/// </summary>
		public enum AxisInfluenced
		{
				X,
				Y,
				Z,
				XYZ
		}
		/// <summary>
		/// Dynamic area zone.
		/// </summary>
		public enum DynamicArea
		{
				FullScreen,
				Left,
				Right,
				Top,
				Bottom,
				TopLeft,
				TopRight,
				BottomLeft,
				BottomRight}
		;
		/// <summary>
		/// Interaction type.
		/// </summary>
		public enum InteractionType
		{
				Direct,
				Include,
				EventNotification,
				DirectAndEvent
		}
		/// <summary>
		/// Broadcast mode for javascript
		/// </summary>
		public enum Broadcast
		{
				SendMessage,
				SendMessageUpwards,
				BroadcastMessage
		}
		/// <summary>
		/// Message name.
		/// </summary>
		private enum MessageName
		{
				On_JoystickMoveStart,
				On_JoystickTouchStart,
				On_JoystickTouchUp,
				On_JoystickMove,
				On_JoystickMoveEnd,
				On_JoystickTap,
				On_JoystickDoubleTap}
		;
	#endregion
	
	#region Members
	
	#region Public Members
	
	#region   property
		private Vector2 joystickAxis;
		/// <summary>
		/// Gets the joystick axis value between -1 & 1...
		/// </summary>
		/// <value>
		/// The joystick axis.
		/// </value>
		public Vector2 JoystickAxis {
				get {
						return this.joystickAxis;
				}
		}	
	
		/// <summary>
		/// Gest or set the touch position.
		/// </summary>
		private Vector2 joystickTouch;

		public Vector2 JoystickTouch {
				get {
						return new Vector2 (this.joystickTouch.x / zoneRadius, this.joystickTouch.y / zoneRadius);
				}
				set {
						float x = Mathf.Clamp (value.x, -1f, 1f) * zoneRadius;
						float y = Mathf.Clamp (value.y, -1f, 1f) * zoneRadius;
						joystickTouch = new Vector2 (x, y);
				}
		}
	
		private Vector2 joystickValue;
		/// <summary>
		/// Gets the joystick value = joystic axis value * jostick speed * Time.deltaTime...
		/// </summary>
		/// <value>
		/// The joystick value.
		/// </value>
		public Vector2 JoystickValue {
				get {
						return this.joystickValue;
				}
		}
	#endregion
	
	#region public joystick properties
	
		/// <summary>
		/// Enable or disable the joystick.
		/// </summary>
		public bool enable = true;

		/// <summary>
		/// Activacte or deactivate the joystick
		/// </summary>
		public bool isActivated = true;

		/// <summary>
		/// The show debug radius area
		/// </summary>
		public bool showDebugRadius = false;
		
		/// <summary>
		/// Use fixed update.
		/// </summary>
		public bool useFixedUpdate = false;
	
		/// <summary>
		///  Disable this lets you skip the GUI layout phase.
		/// </summary>
		public bool isUseGuiLayout = true;	
	
	#endregion
	
	#region Joystick Position & size
		[SerializeField]
		private bool
				dynamicJoystick = false;
		/// <summary>
		/// Gets or sets a value indicating whether this is a dynamic joystick.
		/// When this option is enabled, the joystick will display the location of the touch
		/// </summary>
		/// <value>
		/// <c>true</c> if dynamic joystick; otherwise, <c>false</c>.
		/// </value>
		public bool DynamicJoystick {
				get {
						return this.dynamicJoystick;
				}
				set {
						if (!Application.isPlaying) {
								joystickIndex = -1;
			
								dynamicJoystick = value;
								if (dynamicJoystick) {
										virtualJoystick = false;
								} else {
										virtualJoystick = true;
										joystickCenter = joystickPositionOffset;
								}	
						}
				}
		}
	
		/// <summary>
		/// When the joystick is dynamic mode, this value indicates the area authorized for display
		/// </summary>
		public DynamicArea area = DynamicArea.FullScreen;	
	
		/// <summary>
		/// The joystick anchor.
		/// </summary>
		[SerializeField]
		private JoystickAnchor
				joyAnchor = JoystickAnchor.LowerLeft;

		public JoystickAnchor JoyAnchor {
				get {
						return this.joyAnchor;
				}
				set {
						joyAnchor = value;
						ComputeJoystickAnchor (joyAnchor);
				}
		}	
	
		/// <summary>
		/// The joystick position on the screen
		/// </summary>
		[SerializeField]
		private Vector2
				joystickPositionOffset = Vector2.zero;

		public Vector2 JoystickPositionOffset {
				get {
						return this.joystickPositionOffset;
				}
				set {
			
						joystickPositionOffset = value;
						joystickCenter = joystickPositionOffset;
						ComputeJoystickAnchor (joyAnchor);
				}
		}	
	
		/// <summary>
		/// The zone radius size.
		/// </summary>
		/// 
		[SerializeField]
		private float
				zoneRadius = 100f;

		public float ZoneRadius {
				get {
						return this.zoneRadius;
				}
				set {
						zoneRadius = value;
						ComputeJoystickAnchor (joyAnchor);
				}
		}
	
		[SerializeField]
		private float
				touchSize = 30;
		/// <summary>
		/// Gets or sets the size of the touch.
		/// 
		/// </summary>
		/// <value>
		/// The size of the touch.
		/// </value>
		public float TouchSize {
				get {
						return this.touchSize;
				}
				set {
						touchSize = value;
						if (touchSize > zoneRadius / 2 && restrictArea) {
								touchSize = zoneRadius / 2; 	
						}
						ComputeJoystickAnchor (joyAnchor);
				}
		}
	
		/// <summary>
		/// The dead zone size. While the touch is in this area, the joystick is considered stalled
		/// </summary> 
		public float deadZone = 20;
		[SerializeField]
		private bool
				restrictArea = false;
		/// <summary>
		/// Gets or sets a value indicating whether the touch must be in the radius area.
		/// </summary>
		/// <value>
		/// <c>true</c> if restrict area; otherwise, <c>false</c>.
		/// </value>
		public bool RestrictArea {
				get {
						return this.restrictArea;
				}
				set {
						restrictArea = value;
						if (restrictArea) {
								touchSizeCoef = touchSize;
						} else {
								touchSizeCoef = 0;	
						}
						ComputeJoystickAnchor (joyAnchor);
				}
		}	
	
		/// <summary>
		/// The reset finger exit.
		/// </summary>
		public bool resetFingerExit = false;	
	#endregion
	
	#region Joystick axes properties & event
		/// <summary>
		/// The interaction.
		/// </summary>
		[SerializeField]
		private  InteractionType
				interaction = InteractionType.Direct;

		public InteractionType Interaction {
				get {
						return this.interaction;
				}
				set {
						interaction = value;
						if (interaction == InteractionType.Direct || interaction == InteractionType.Include) {
								useBroadcast = false;	
						}
				}
		}		
	
		/// <summary>
		/// The use broadcast for javascript
		/// </summary>
		public bool useBroadcast = false;
	
		/// <summary>
		/// The message sending mode fro broacast
		/// </summary>
		public Broadcast messageMode;
	
		// Messaging
		/// <summary>
		/// The receiver gameobject when you're in broacast mode for events
		/// </summary>
		public GameObject receiverGameObject; 
	
		/// <summary>
		/// The speed of each joystick axis
		/// </summary>
		public Vector2 speed;
	
	#region X axis
		public bool enableXaxis = true;
		[SerializeField]
		private Transform
				xAxisTransform;
		/// <summary>
		/// Gets or sets the transform influenced by x axis of the joystick.
		/// </summary>
		/// <value>
		/// The X axis transform.
		/// </value>
		public Transform XAxisTransform {
				get {
						return this.xAxisTransform;
				}
				set {
						xAxisTransform = value;
						if (xAxisTransform != null) {
								xAxisCharacterController = xAxisTransform.GetComponent<CharacterController> ();
						} else {
								xAxisCharacterController = null;	
								xAxisGravity = 0;
						}
				}
		}	
	
		/// <summary>
		/// The character controller attached to the X axis transform (if exist)
		/// </summary>
		public CharacterController xAxisCharacterController;
	
	
		/// <summary>
		/// The gravity.
		/// </summary>
		public float xAxisGravity = 0;
		[SerializeField]
		private PropertiesInfluenced
				xTI;
		/// <summary>
		/// The Property influenced by the x axis joystick
		/// </summary>
		public PropertiesInfluenced XTI {
				get {
						return this.xTI;
				}
				set {
						xTI = value;
						if (xTI != PropertiesInfluenced.RotateLocal) {
								enableXAutoStab = false;
								enableXClamp = false;
						}
				}
		}	
	
		/// <summary>
		/// The axis influenced by the x axis joystick
		/// </summary>
		public AxisInfluenced xAI;
		/// <summary>
		/// Inverse X axis.
		/// </summary>
		public bool inverseXAxis = false;
		/// <summary>
		/// The limit angle.
		/// </summary>
		public bool enableXClamp = false;

		/// <summary>
		/// The clamp X max.
		/// </summary>
		public float clampXMax;
		/// <summary>
		/// The clamp X minimum.
		/// </summary>
		public float clampXMin;
	
		/// <summary>
		/// The enable X auto stab.
		/// </summary>
		public bool enableXAutoStab = false;
		[SerializeField]
		private float
				thresholdX = 0.01f;
		/// <summary>
		/// Gets or sets the threshold x.
		/// </summary>
		/// <value>
		/// The threshold x.
		/// </value>
		public float ThresholdX {
				get {
						return this.thresholdX;
				}
				set {
						if (value <= 0) {
								thresholdX = value * -1f;
						} else {
								thresholdX = value;
						}
				}
		}
	
		[SerializeField]
		private float
				stabSpeedX = 20f;	
		/// <summary>
		/// Gets or sets the stab speed x.
		/// </summary>
		/// <value>
		/// The stab speed x.
		/// </value>
		public float StabSpeedX {
				get {
						return this.stabSpeedX;
				}
				set {
						if (value <= 0) {
								stabSpeedX = value * -1f;
						} else {
								stabSpeedX = value;
						}
				}
		}
	#endregion
	
	#region Y axis
		public bool enableYaxis = true;
		[SerializeField]
		private Transform
				yAxisTransform;
		/// <summary>
		/// Gets or sets the transform influenced by y axis of the joystick.
		/// </summary>
		/// <value>
		/// The Y axis transform.
		/// </value>
		public Transform YAxisTransform {
				get {
						return this.yAxisTransform;
				}
				set {
						yAxisTransform = value;
						if (yAxisTransform != null) {
								yAxisCharacterController = yAxisTransform.GetComponent<CharacterController> ();
						} else {
								yAxisCharacterController = null;
								yAxisGravity = 0;
						}
				}
		}	
	
		/// <summary>
		/// The character controller attached to the X axis transform (if exist)
		/// </summary>
		public CharacterController yAxisCharacterController;
	
		/// <summary>
		/// The y axis gravity.
		/// </summary>
		public float yAxisGravity = 0;

		/// <summary>
		/// The Property influenced by the y axis joystick
		/// </summary>
		[SerializeField]
		private PropertiesInfluenced
				yTI;

		public PropertiesInfluenced YTI {
				get {
						return this.yTI;
				}
				set {
						yTI = value;
						if (yTI != PropertiesInfluenced.RotateLocal) {
								enableYAutoStab = false;
								enableYClamp = false;
						}
				}
		}	
	
		/// <summary>
		/// The axis influenced by the y axis joystick
		/// </summary>
		public AxisInfluenced yAI;
	
		/// <summary>
		/// Inverse Y axis.
		/// </summary>	
		public bool inverseYAxis = false;
		/// <summary>
		/// The enable Y clamp.
		/// </summary>
		public bool enableYClamp = false;
		/// <summary>
		/// The clamp Y max.
		/// </summary>
		public float clampYMax;
		/// <summary>
		/// The clamp Y minimum.
		/// </summary>
		public float clampYMin;
		/// <summary>
		/// The enable Y auto stab.
		/// </summary>
		public bool enableYAutoStab = false;
		[SerializeField]
		private float
				thresholdY = 0.01f;
		/// <summary>
		/// Gets or sets the threshold y.
		/// </summary>
		/// <value>
		/// The threshold y.
		/// </value>
		public float ThresholdY {
				get {
						return this.thresholdY;
				}
				set {
						if (value <= 0) {
								thresholdY = value * -1f;
						} else {
								thresholdY = value;
						}
				}
		}
	
		[SerializeField]
		private float
				stabSpeedY = 20f;
		/// <summary>
		/// Gets or sets the stab speed y.
		/// </summary>
		/// <value>
		/// The stab speed y.
		/// </value>
		public float StabSpeedY {
				get {
						return this.stabSpeedY;
				}
				set {
						if (value <= 0) {
								stabSpeedY = value * -1f;
						} else {
								stabSpeedY = value;
						}
						;
				}
		}

	#endregion	

		/// <summary>
		/// The enable smoothing.When smoothing is enabled, resets the joystick slowly in the start position
		/// </summary>
		public bool enableSmoothing = false;
		[SerializeField]
		public Vector2
				smoothing = new Vector2 (2f, 2f);
		/// <summary>
		/// Gets or sets the smoothing values
		/// </summary>
		/// <value>
		/// The smoothing.
		/// </value>
		public Vector2 Smoothing {
				get {
						return this.smoothing;
				}
				set {
						smoothing = value;
						if (smoothing.x < 0f) {
								smoothing.x = 0;
						}
						if (smoothing.y < 0) {
								smoothing.y = 0;	
						}
				}
		}
	
		/// <summary>
		/// The enable inertia. Inertia simulates sliding movements (like a hovercraft, for example)
		/// </summary>
		public bool enableInertia = false;
		[SerializeField]
		public Vector2
				inertia = new Vector2 (100, 100);
		/// <summary>
		/// Gets or sets the inertia values
		/// </summary>
		/// <value>
		/// The inertia.
		/// </value>
		public Vector2 Inertia {
				get {
						return this.inertia;
				}
				set {
						inertia = value;
						if (inertia.x <= 0) {
								inertia.x = 1;
						}
						if (inertia.y <= 0) {
								inertia.y = 1;
						}
			
				}
		}
	#endregion

	#region Joystick textures & color
		/// <summary>
		/// The GUI depth.
		/// </summary>
		public int guiDepth = 0;
	
		// Joystick Texture
		/// <summary>
		/// The show zone.
		/// </summary>
		public bool showZone = true;
		/// <summary>
		/// The show touch.
		/// </summary>
		public bool showTouch = true;
		/// <summary>
		/// The show dead zone.
		/// </summary>
		public bool showDeadZone = true;
		/// <summary>
		/// The area texture.
		/// </summary>
		public Texture areaTexture;
		/// <summary>
		/// The color of the area.
		/// </summary>
		public Color areaColor = Color.white;
		/// <summary>
		/// The touch texture.
		/// </summary>
		public Texture touchTexture;
		/// <summary>
		/// The color of the touch.
		/// </summary>
		public Color touchColor = Color.white;
		/// <summary>
		/// The dead texture.
		/// </summary>
		public Texture deadTexture;	
	#endregion

	#region Inspector
		public bool showProperties = true;
		public bool showInteraction = false;
		public bool showAppearance = false;
		public bool showPosition = true;
	#endregion

	#endregion

	#region private members
		// Joystick properties
		private Vector2 joystickCenter;
		private Rect areaRect;
		private Rect deadRect;
		private Vector2 anchorPosition = Vector2.zero;
		private bool virtualJoystick = true;
		private int joystickIndex = -1;
		private float touchSizeCoef = 0;
		private bool sendEnd = true;
		private float startXLocalAngle = 0;
		private float startYLocalAngle = 0;
	#endregion
	
	#endregion
	
	#region Monobehaviour methods
		void OnEnable ()
		{
				EasyTouch.On_TouchStart += On_TouchStart;
				EasyTouch.On_TouchUp += On_TouchUp;
				EasyTouch.On_TouchDown += On_TouchDown;
				EasyTouch.On_SimpleTap += On_SimpleTap;
				EasyTouch.On_DoubleTap += On_DoubleTap;
		}

		void OnDisable ()
		{
				EasyTouch.On_TouchStart -= On_TouchStart;
				EasyTouch.On_TouchUp -= On_TouchUp;
				EasyTouch.On_TouchDown -= On_TouchDown;	
				EasyTouch.On_SimpleTap -= On_SimpleTap;
				EasyTouch.On_DoubleTap -= On_DoubleTap;	
		
				if (Application.isPlaying) {
						EasyTouch.RemoveReservedArea (areaRect);
				}
		}
		
		void OnDestroy ()
		{
				EasyTouch.On_TouchStart -= On_TouchStart;
				EasyTouch.On_TouchUp -= On_TouchUp;
				EasyTouch.On_TouchDown -= On_TouchDown;	
				EasyTouch.On_SimpleTap -= On_SimpleTap;
				EasyTouch.On_DoubleTap -= On_DoubleTap;	
		
				if (Application.isPlaying) {
						EasyTouch.RemoveReservedArea (areaRect);
				}
		}
			
		void Start ()
		{
					
				if (!dynamicJoystick) {
						joystickCenter = joystickPositionOffset;
						ComputeJoystickAnchor (joyAnchor);
						virtualJoystick = true;
				} else {
						virtualJoystick = false;	
				}
				VirtualScreen.ComputeVirtualScreen ();

				startXLocalAngle = GetStartAutoStabAngle (xAxisTransform, xAI);
				startYLocalAngle = GetStartAutoStabAngle (yAxisTransform, yAI);	
		}
	
		void Update ()
		{
				if (!useFixedUpdate && enable) {
						UpdateJoystick ();	
				}
		}
	
		void FixedUpdate ()
		{
				if (useFixedUpdate && enable) {
						UpdateJoystick ();	
				}		
		}
	
		void UpdateJoystick ()
		{
		
				if (Application.isPlaying) {
			
						if (isActivated) {
				
								if ((joystickIndex == -1) || (joystickAxis == Vector2.zero && joystickIndex > -1)) {
										if (enableXAutoStab) {
												DoAutoStabilisation (xAxisTransform, xAI, thresholdX, stabSpeedX, startXLocalAngle);
										}
										if (enableYAutoStab) {
												DoAutoStabilisation (yAxisTransform, yAI, thresholdY, stabSpeedY, startYLocalAngle);
										}	
								}
				
								if (!dynamicJoystick) {
										joystickCenter = joystickPositionOffset;
								}
				
								// Reset to initial position
								if (joystickIndex == -1) {
										if (!enableSmoothing) {
												joystickTouch = Vector2.zero;
										} else { 
												if (joystickTouch.sqrMagnitude > 0.0001) {
														joystickTouch = new Vector2 (joystickTouch.x - joystickTouch.x * smoothing.x * Time.deltaTime, joystickTouch.y - joystickTouch.y * smoothing.y * Time.deltaTime);	
												} else {
														joystickTouch = Vector2.zero;
												}
										}
								}
				
				
								// Joystick Axis & dead zone
								Vector2 oldJoystickAxis = new Vector2 (joystickAxis.x, joystickAxis.y);
								float deadCoef = ComputeDeadZone ();
								joystickAxis = new Vector2 (joystickTouch.x * deadCoef, joystickTouch.y * deadCoef);				
				
								// Inverse axis ?
								if (inverseXAxis) {
										joystickAxis.x *= -1;	
								}
								if (inverseYAxis) {
										joystickAxis.y *= -1;	
								}
				
								// Joystick Value
								Vector2 realvalue = new Vector2 (speed.x * joystickAxis.x, speed.y * joystickAxis.y);
								if (enableInertia) {
										Vector2 tmp = (realvalue - joystickValue);
										tmp.x /= inertia.x;
										tmp.y /= inertia.y;
										joystickValue += tmp;
					
								} else {
										joystickValue = realvalue;	
					
								}

								// Start moving
								if (oldJoystickAxis == Vector2.zero && joystickAxis != Vector2.zero) {
										if (interaction != InteractionType.Direct && interaction != InteractionType.Include) {
												CreateEvent (MessageName.On_JoystickMoveStart);	
										}
								}				
				
								// interaction manager
								UpdateGravity ();
	
				
								if (joystickAxis != Vector2.zero) {
										sendEnd = false;
										switch (interaction) {
										case InteractionType.Direct:
												UpdateDirect ();
												break;
										case InteractionType.EventNotification:
												CreateEvent (MessageName.On_JoystickMove);
												break;
										case InteractionType.DirectAndEvent:
												UpdateDirect ();
												CreateEvent (MessageName.On_JoystickMove);
												break;
										}
								} else {
										if (!sendEnd) {
												CreateEvent (MessageName.On_JoystickMoveEnd);
												sendEnd = true;
										}
								
								}
						}
				}	
		}
	
		void OnGUI ()
		{
							
				if (enable) {
	
						GUI.depth = guiDepth;
			
						useGUILayout = isUseGuiLayout;
			
						if (dynamicJoystick && Application.isEditor && !Application.isPlaying) {
								switch (area) {
								case DynamicArea.Bottom:	
										ComputeJoystickAnchor (JoystickAnchor.LowerCenter);
										break;
								case DynamicArea.BottomLeft:
										ComputeJoystickAnchor (JoystickAnchor.LowerLeft);
										break;
								case DynamicArea.BottomRight:
										ComputeJoystickAnchor (JoystickAnchor.LowerRight);
										break;
								case DynamicArea.FullScreen:
										ComputeJoystickAnchor (JoystickAnchor.MiddleCenter);
										break;
								case DynamicArea.Left:
										ComputeJoystickAnchor (JoystickAnchor.MiddleLeft);
										break;
								case DynamicArea.Right:
										ComputeJoystickAnchor (JoystickAnchor.MiddleRight);
										break;
								case DynamicArea.Top:
										ComputeJoystickAnchor (JoystickAnchor.UpperCenter);
										break;
								case DynamicArea.TopLeft:
										ComputeJoystickAnchor (JoystickAnchor.UpperLeft);
										break;
								case DynamicArea.TopRight:
										ComputeJoystickAnchor (JoystickAnchor.UpperRight);
										break;
								}
						}
			
						if (Application.isEditor && !Application.isPlaying) {
								VirtualScreen.ComputeVirtualScreen ();
								ComputeJoystickAnchor (joyAnchor);
						}
			
						VirtualScreen.SetGuiScaleMatrix ();
			
			
			
						// area zone
						if ((showZone && areaTexture != null && !dynamicJoystick) || (showZone && dynamicJoystick && virtualJoystick && areaTexture != null) 
								|| (dynamicJoystick && Application.isEditor && !Application.isPlaying)) {
								if (isActivated) {
										GUI.color = areaColor;
					
										if (Application.isPlaying && !dynamicJoystick) {
												EasyTouch.RemoveReservedArea (areaRect);
												EasyTouch.AddReservedArea (areaRect);
										}
								} else {
										GUI.color = new Color (areaColor.r, areaColor.g, areaColor.b, 0.2f);	
										if (Application.isPlaying && !dynamicJoystick) {
												EasyTouch.RemoveReservedArea (areaRect);	
										}
								}		
				
								if (showDebugRadius && Application.isEditor) {
										GUI.Box (areaRect, "");				
								}
				
								GUI.DrawTexture (areaRect, areaTexture, ScaleMode.StretchToFill, true);
						}
			
			
						// area touch
						if ((showTouch && touchTexture != null && !dynamicJoystick) || (showTouch && dynamicJoystick && virtualJoystick && touchTexture != null) 
								|| (dynamicJoystick && Application.isEditor && !Application.isPlaying)) {
								if (isActivated) {
										GUI.color = touchColor;
								} else {
										GUI.color = new Color (touchColor.r, touchColor.g, touchColor.b, 0.2f);	
								}			
								GUI.DrawTexture (new Rect (anchorPosition.x + joystickCenter.x + (joystickTouch.x - touchSize), anchorPosition.y + joystickCenter.y - (joystickTouch.y + touchSize), touchSize * 2, touchSize * 2), touchTexture, ScaleMode.ScaleToFit, true);
						}	
	
						// dead zone
						if ((showDeadZone && deadTexture != null && !dynamicJoystick) || (showDeadZone && dynamicJoystick && virtualJoystick && deadTexture != null) 
								|| (dynamicJoystick && Application.isEditor && !Application.isPlaying)) {			
								GUI.DrawTexture (deadRect, deadTexture, ScaleMode.ScaleToFit, true);
						}	
			
						GUI.color = Color.white;
				} else {
						EasyTouch.RemoveReservedArea (areaRect);	
				}
		}
	
		void OnDrawGizmos ()
		{
		}
	
	#endregion
	
	#region Private methods
		void CreateEvent (MessageName message)
		{
		
				MovingJoystick move = new MovingJoystick ();
				move.joystickName = gameObject.name;
				move.joystickAxis = joystickAxis;
				move.joystickValue = joystickValue;
				move.joystick = this;
		
				//
				if (!useBroadcast) {
						switch (message) {
						case MessageName.On_JoystickMoveStart:
								if (On_JoystickMoveStart != null) {
										On_JoystickMoveStart (move);	
								}
								break;					
						case MessageName.On_JoystickMove:
								if (On_JoystickMove != null) {
										On_JoystickMove (move);	
								}
								break;
						case MessageName.On_JoystickMoveEnd:
								if (On_JoystickMoveEnd != null) {
										On_JoystickMoveEnd (move);	
								}
								break;	
						case MessageName.On_JoystickTouchStart:
								if (On_JoystickTouchStart != null) {
										On_JoystickTouchStart (move);	
								}
								break;
						case MessageName.On_JoystickTap:
								if (On_JoystickTap != null) {
										On_JoystickTap (move);	
								}
								break;				
				
						case MessageName.On_JoystickDoubleTap:
								if (On_JoystickDoubleTap != null) {
										On_JoystickDoubleTap (move);	
								}
								break;	
						case MessageName.On_JoystickTouchUp:
								if (On_JoystickTouchUp != null) {
										On_JoystickTouchUp (move);	
								}
								break;
						}			
				} else if (useBroadcast) {
						if (receiverGameObject != null) {
								switch (messageMode) {
								case Broadcast.BroadcastMessage:
										receiverGameObject.BroadcastMessage (message.ToString (), move, SendMessageOptions.DontRequireReceiver);
										break;
								case Broadcast.SendMessage:
										receiverGameObject.SendMessage (message.ToString (), move, SendMessageOptions.DontRequireReceiver);
										break;
								case Broadcast.SendMessageUpwards:
										receiverGameObject.SendMessageUpwards (message.ToString (), move, SendMessageOptions.DontRequireReceiver);
										break;
								}
						} else {
								Debug.LogError ("Joystick : " + gameObject.name + " : you must setup receiver gameobject");	
						}
				}
		
		}
	
		void UpdateDirect ()
		{
		
				// X joystick axis
				if (xAxisTransform != null) {
						// Axis influenced
						Vector3 axis = GetInfluencedAxis (xAI);
						// Action
						DoActionDirect (xAxisTransform, xTI, axis, joystickValue.x, xAxisCharacterController);

						if (enableXClamp && xTI == PropertiesInfluenced.RotateLocal) {
								DoAngleLimitation (xAxisTransform, xAI, clampXMin, clampXMax, startXLocalAngle);
						}
				}
		
		
				// y joystick axis
				if (YAxisTransform != null) {
						// Axis
						Vector3 axis = GetInfluencedAxis (yAI);
						// Action
						DoActionDirect (yAxisTransform, yTI, axis, joystickValue.y, yAxisCharacterController);
			
						if (enableYClamp && yTI == PropertiesInfluenced.RotateLocal) {
								DoAngleLimitation (yAxisTransform, yAI, clampYMin, clampYMax, startYLocalAngle);
						}
			
				}
		
		}
	
		void UpdateGravity ()
		{
				// Gravity
				if (xAxisCharacterController != null && xAxisGravity > 0) {
						xAxisCharacterController.Move (Vector3.down * xAxisGravity * Time.deltaTime);	
				}
			
				if (yAxisCharacterController != null && yAxisGravity > 0) {
						yAxisCharacterController.Move (Vector3.down * yAxisGravity * Time.deltaTime);
				}		
		}
	
		Vector3 GetInfluencedAxis (AxisInfluenced axisInfluenced)
		{
		
				Vector3 axis = Vector3.zero;
		
				switch (axisInfluenced) {
				case AxisInfluenced.X:
						axis = Vector3.right;
						break;
				case AxisInfluenced.Y:
						axis = Vector3.up;
						break;
				case AxisInfluenced.Z:
						axis = Vector3.forward;
						break;
				case AxisInfluenced.XYZ:
						axis = Vector3.one;
						break;
				
				}	
		
				return axis;
		}
	
		void DoActionDirect (Transform axisTransform, PropertiesInfluenced inlfuencedProperty, Vector3 axis, float sensibility, CharacterController charact)
		{
		

				switch (inlfuencedProperty) {
			
				case PropertiesInfluenced.Rotate:
						axisTransform.Rotate (axis * sensibility * Time.deltaTime, Space.World);
						break;	
			
				case PropertiesInfluenced.RotateLocal:
						axisTransform.Rotate (axis * sensibility * Time.deltaTime, Space.Self);
						break;
			
				case PropertiesInfluenced.Translate:
						if (charact == null) {
								axisTransform.Translate (axis * sensibility * Time.deltaTime, Space.World);
						} else {
								charact.Move (axis * sensibility * Time.deltaTime);
						}
						break;
			
				case PropertiesInfluenced.TranslateLocal:
						if (charact == null) {
								axisTransform.Translate (axis * sensibility * Time.deltaTime, Space.Self);
						} else {
					
								charact.Move (charact.transform.TransformDirection (axis) * sensibility * Time.deltaTime);
						}
						break;	
			
				case PropertiesInfluenced.Scale:
						axisTransform.localScale += axis * sensibility * Time.deltaTime;
						break;
				}
		
		}
	
		void DoAngleLimitation (Transform axisTransform, AxisInfluenced axisInfluenced, float clampMin, float clampMax, float startAngle)
		{
		
				float angle = 0;
		
				switch (axisInfluenced) {
				case AxisInfluenced.X:
						angle = axisTransform.localRotation.eulerAngles.x;
						break;
				case AxisInfluenced.Y:
						angle = axisTransform.localRotation.eulerAngles.y;
						break;
				case AxisInfluenced.Z:
						angle = axisTransform.localRotation.eulerAngles.z;
						break;			
				}
		
				if (angle <= 360 && angle >= 180) {
						angle = angle - 360;	
				}
		
				//angle = Mathf.Clamp (angle, startAngle-clampMax, clampMin+startAngle);
				angle = Mathf.Clamp (angle, -clampMax, clampMin);
		
		
				switch (axisInfluenced) {
				case AxisInfluenced.X:
						axisTransform.localEulerAngles = new Vector3 (angle, axisTransform.localEulerAngles.y, axisTransform.localEulerAngles.z);
						break;	
				case AxisInfluenced.Y:
						axisTransform.localEulerAngles = new Vector3 (axisTransform.localEulerAngles.x, angle, axisTransform.localEulerAngles.z);
						break;
				case AxisInfluenced.Z:
						axisTransform.localEulerAngles = new Vector3 (axisTransform.localEulerAngles.x, axisTransform.localEulerAngles.y, angle);
						break;	
								
				}
		
		}
	
		void DoAutoStabilisation (Transform axisTransform, AxisInfluenced axisInfluenced, float threshold, float speed, float startAngle)
		{
	
				float angle = 0;
				switch (axisInfluenced) {
				case AxisInfluenced.X:
						angle = axisTransform.localRotation.eulerAngles.x;
						break;
				case AxisInfluenced.Y:
						angle = axisTransform.localRotation.eulerAngles.y;
						break;
				case AxisInfluenced.Z:
						angle = axisTransform.localRotation.eulerAngles.z;
						break;			
				}
		
		
				if (angle <= 360 && angle >= 180) {
						angle = angle - 360;	
				}		
		
		
				if (angle > startAngle - threshold || angle < startAngle + threshold) {
			
						float axis = 0;
						Vector3 stabAngle = Vector3.zero;
			
						if (angle > startAngle - threshold) {
								axis = angle + speed / 100f * Mathf.Abs (angle - startAngle) * Time.deltaTime * -1;
						}
		
		
						if (angle < startAngle + threshold) {
								axis = angle + speed / 100f * Mathf.Abs (angle - startAngle) * Time.deltaTime;
						}
		
						switch (axisInfluenced) {
						case AxisInfluenced.X:	
								stabAngle = new Vector3 (axis, axisTransform.localRotation.eulerAngles.y, axisTransform.localRotation.eulerAngles.z);
								break;
						case AxisInfluenced.Y:	
								stabAngle = new Vector3 (axisTransform.localRotation.eulerAngles.x, axis, axisTransform.localRotation.eulerAngles.z);
								break;
						case AxisInfluenced.Z:	
								stabAngle = new Vector3 (axisTransform.localRotation.eulerAngles.x, axisTransform.localRotation.eulerAngles.y, axis);
								break;
						}
			
						axisTransform.localRotation = Quaternion.Euler (stabAngle);	
				}
		}
	
		float GetStartAutoStabAngle (Transform axisTransform, AxisInfluenced axisInfluenced)
		{
		
				float angle = 0;
		
				if (axisTransform != null) {
						switch (axisInfluenced) {
						case AxisInfluenced.X:
								angle = axisTransform.localRotation.eulerAngles.x;
								break;
						case AxisInfluenced.Y:
								angle = axisTransform.localRotation.eulerAngles.y;
								break;
						case AxisInfluenced.Z:
								angle = axisTransform.localRotation.eulerAngles.z;
								break;			
						}	
			
						if (angle <= 360 && angle >= 180) {
								angle = angle - 360;	
						}
				}
		
				return angle;
		}
	
		float ComputeDeadZone ()
		{
		
				float dead = 0;
				float dist = Mathf.Max (joystickTouch.magnitude, 0.1f);
		
				if (restrictArea) {
						dead = Mathf.Max (dist - deadZone, 0) / (zoneRadius - touchSize - deadZone) / dist;
				} else {
						dead = Mathf.Max (dist - deadZone, 0) / (zoneRadius - deadZone) / dist;
				}		
		
				return dead;
		}
	
		void ComputeJoystickAnchor (JoystickAnchor anchor)
		{
	
				float touch = 0;
				if (!restrictArea) {
						touch = touchSize;	
				}
				// Anchor position
				switch (anchor) {
				case JoystickAnchor.UpperLeft:
						anchorPosition = new Vector2 (zoneRadius + touch, zoneRadius + touch);
						break;
				case JoystickAnchor.UpperCenter:
						anchorPosition = new Vector2 (VirtualScreen.width / 2, zoneRadius + touch);
						break;
				case JoystickAnchor.UpperRight:
						anchorPosition = new Vector2 (VirtualScreen.width - zoneRadius - touch, zoneRadius + touch);
						break;
			
			
				case JoystickAnchor.MiddleLeft:
						anchorPosition = new Vector2 (zoneRadius + touch, VirtualScreen.height / 2);
						break;
				case JoystickAnchor.MiddleCenter:
						anchorPosition = new Vector2 (VirtualScreen.width / 2, VirtualScreen.height / 2);
						break;
				case JoystickAnchor.MiddleRight:
						anchorPosition = new Vector2 (VirtualScreen.width - zoneRadius - touch, VirtualScreen.height / 2);
						break;
			
				case JoystickAnchor.LowerLeft:
						anchorPosition = new Vector2 (zoneRadius + touch, VirtualScreen.height - zoneRadius - touch);
						break;
				case JoystickAnchor.LowerCenter:
						anchorPosition = new Vector2 (VirtualScreen.width / 2, VirtualScreen.height - zoneRadius - touch);
						break;
				case JoystickAnchor.LowerRight:
						anchorPosition = new Vector2 (VirtualScreen.width - zoneRadius - touch, VirtualScreen.height - zoneRadius - touch);
						break;	
			
				case JoystickAnchor.None:
						anchorPosition = Vector2.zero;
						break;
				}
				
				//joystick rect

				areaRect = new Rect (anchorPosition.x + joystickCenter.x - zoneRadius, anchorPosition.y + joystickCenter.y - zoneRadius, zoneRadius * 2, zoneRadius * 2);

				deadRect = new Rect (anchorPosition.x + joystickCenter.x - deadZone, anchorPosition.y + joystickCenter.y - deadZone, deadZone * 2, deadZone * 2);
		
		}
	#endregion
	
	#region EasyTouch events
		// Touch start
		void On_TouchStart (Gesture gesture)
		{
					
				if ((!gesture.isHoverReservedArea && dynamicJoystick) || !dynamicJoystick) {

						if (isActivated) {
								if (!dynamicJoystick) {
				
										Vector2 center = new Vector2 ((anchorPosition.x + joystickCenter.x) * VirtualScreen.xRatio, (VirtualScreen.height - anchorPosition.y - joystickCenter.y) * VirtualScreen.yRatio);
					
										if ((gesture.position - center).sqrMagnitude < (zoneRadius * VirtualScreen.xRatio) * (zoneRadius * VirtualScreen.xRatio)) {
												joystickIndex = gesture.fingerIndex;
												CreateEvent (MessageName.On_JoystickTouchStart);
										}			
								} else {
										if (!virtualJoystick) {
						
												#region area restriction
												switch (area) {
												// full
												case DynamicArea.FullScreen:
														virtualJoystick = true;
														;
														break;
												// bottom
												case DynamicArea.Bottom:
														if (gesture.position.y < Screen.height / 2) {
																virtualJoystick = true;	
														}
														break;
												// top
												case DynamicArea.Top:
														if (gesture.position.y > Screen.height / 2) {
																virtualJoystick = true;	
														}
														break;
												// Right
												case DynamicArea.Right:
														if (gesture.position.x > Screen.width / 2) {
																virtualJoystick = true;	
														}
														break;
												// Left
												case DynamicArea.Left:
														if (gesture.position.x < Screen.width / 2) {
																virtualJoystick = true;	
														}
														break;				
							
												// top Right
												case DynamicArea.TopRight:
														if (gesture.position.y > Screen.height / 2 && gesture.position.x > Screen.width / 2) {
																virtualJoystick = true;	
														}
														break;	
												// top Left
												case DynamicArea.TopLeft:
														if (gesture.position.y > Screen.height / 2 && gesture.position.x < Screen.width / 2) {
																virtualJoystick = true;	
														}
														break;					
												// bottom Right
												case DynamicArea.BottomRight:
														if (gesture.position.y < Screen.height / 2 && gesture.position.x > Screen.width / 2) {
																virtualJoystick = true;	
														}
														break;					
												// bottom left
												case DynamicArea.BottomLeft:
														if (gesture.position.y < Screen.height / 2 && gesture.position.x < Screen.width / 2) {
																virtualJoystick = true;	
														}
														break;							
												}				
												#endregion
						
												if (virtualJoystick) {
														joystickCenter = new Vector2 (gesture.position.x / VirtualScreen.xRatio, VirtualScreen.height - gesture.position.y / VirtualScreen.yRatio);
														JoyAnchor = JoystickAnchor.None;
														joystickIndex = gesture.fingerIndex;
												}	
										}
								}
			
						}
				}
		}
	
		// Simple tap
		void On_SimpleTap (Gesture gesture)
		{
				if ((!gesture.isHoverReservedArea && dynamicJoystick) || !dynamicJoystick) {
						if (isActivated) {
								if (gesture.fingerIndex == joystickIndex) {
										CreateEvent (MessageName.On_JoystickTap);	
								}	
						}
				}
		}
	
		// Double tap
		void On_DoubleTap (Gesture gesture)
		{
				if ((!gesture.isHoverReservedArea && dynamicJoystick) || !dynamicJoystick) {
						if (isActivated) {
								if (gesture.fingerIndex == joystickIndex) {
										CreateEvent (MessageName.On_JoystickDoubleTap);	
								}
						}
				}
		}
	
		// Joystick move
		void On_TouchDown (Gesture gesture)
		{
		
				if ((!gesture.isHoverReservedArea && dynamicJoystick) || !dynamicJoystick) {
			
						if (isActivated) {

				  
								//Debug.Log (joystickCenter);
								Vector2 newPos = (joystickTouch + gesture.deltaPosition);
						
								//Debug.Log(dir);
								if (newPos.magnitude > zoneRadius) {

										float move = zoneRadius - newPos.magnitude;
									//Debug.Log(move);
										Vector2 moveVec2 = newPos.normalized * move;
										joystickCenter.x -= moveVec2.x;
										joystickCenter.y += moveVec2.y;
										//
										JoyAnchor = JoystickAnchor.None;
					
								}



								Vector2 center = new Vector2 ((anchorPosition.x + joystickCenter.x) * VirtualScreen.xRatio, (VirtualScreen.height - (anchorPosition.y + joystickCenter.y)) * VirtualScreen.yRatio);
								if (gesture.fingerIndex == joystickIndex) {
										if (((gesture.position - center).sqrMagnitude < (zoneRadius * VirtualScreen.xRatio) * (zoneRadius * VirtualScreen.xRatio) && resetFingerExit) || !resetFingerExit) {
						
						
												joystickTouch = new Vector2 (gesture.position.x, gesture.position.y) - center;
												joystickTouch = new Vector2 (joystickTouch.x / VirtualScreen.xRatio, joystickTouch.y / VirtualScreen.yRatio);
						
												if (!enableXaxis) {
														joystickTouch.x = 0;
												}
							
												if (!enableYaxis) {
														joystickTouch.y = 0;
												}
						
												if ((joystickTouch / (zoneRadius - touchSizeCoef)).sqrMagnitude > 1) {
														joystickTouch.Normalize ();


														joystickTouch *= zoneRadius - touchSizeCoef;
												}
										} else {
												On_TouchUp (gesture);	
										}
								}
						}
				}
		}
	
		// Touch end
		void On_TouchUp (Gesture gesture)
		{
		
				if ((!gesture.isHoverReservedArea && dynamicJoystick) || !dynamicJoystick) {
						if (isActivated) {
								if (gesture.fingerIndex == joystickIndex) {
										joystickIndex = -1;
										if (dynamicJoystick) {
						
												virtualJoystick = false;	
										}
										CreateEvent (MessageName.On_JoystickTouchUp);
								}
						}
				}
		}

	#endregion
	
}

https://gist.github.com/dongliang/85ae732b3d176d1a8eed



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值