mergemilitary/Assets/ThirdPlugins/EasyTouchBundle/EasyTouchControls/Plugins/ETCJoystick.cs

781 lines
20 KiB
C#

/***********************************************
EasyTouch Controls
Copyright © 2016 The Hedgehog Team
http://www.thehedgehogteam.com/Forum/
The.Hedgehog.Team@gmail.com
**********************************************/
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
[System.Serializable]
public class ETCJoystick : ETCBase,IPointerEnterHandler,IDragHandler, IBeginDragHandler, IPointerDownHandler, IPointerUpHandler {
#region Unity Events
[System.Serializable] public class OnMoveStartHandler : UnityEvent{}
[System.Serializable] public class OnMoveSpeedHandler : UnityEvent<Vector2> { }
[System.Serializable] public class OnMoveHandler : UnityEvent<Vector2> { }
[System.Serializable] public class OnMoveEndHandler : UnityEvent{ }
[System.Serializable] public class OnTouchStartHandler : UnityEvent{}
[System.Serializable] public class OnTouchUpHandler : UnityEvent{ }
[System.Serializable] public class OnDownUpHandler : UnityEvent{ }
[System.Serializable] public class OnDownDownHandler : UnityEvent{ }
[System.Serializable] public class OnDownLeftHandler : UnityEvent{ }
[System.Serializable] public class OnDownRightHandler : UnityEvent{ }
[System.Serializable] public class OnPressUpHandler : UnityEvent{ }
[System.Serializable] public class OnPressDownHandler : UnityEvent{ }
[System.Serializable] public class OnPressLeftHandler : UnityEvent{ }
[System.Serializable] public class OnPressRightHandler : UnityEvent{ }
[SerializeField] public OnMoveStartHandler onMoveStart;
[SerializeField] public OnMoveHandler onMove;
[SerializeField] public OnMoveSpeedHandler onMoveSpeed;
[SerializeField] public OnMoveEndHandler onMoveEnd;
[SerializeField] public OnTouchStartHandler onTouchStart;
[SerializeField] public OnTouchUpHandler onTouchUp;
[SerializeField] public OnDownUpHandler OnDownUp;
[SerializeField] public OnDownDownHandler OnDownDown;
[SerializeField] public OnDownLeftHandler OnDownLeft;
[SerializeField] public OnDownRightHandler OnDownRight;
[SerializeField] public OnDownUpHandler OnPressUp;
[SerializeField] public OnDownDownHandler OnPressDown;
[SerializeField] public OnDownLeftHandler OnPressLeft;
[SerializeField] public OnDownRightHandler OnPressRight;
#endregion
#region Enumeration
public enum JoystickArea { UserDefined,FullScreen, Left,Right,Top, Bottom, TopLeft, TopRight, BottomLeft, BottomRight};
public enum JoystickType {Dynamic, Static};
public enum RadiusBase {Width, Height, UserDefined};
#endregion
#region Members
#region Public members
public JoystickType joystickType;
public bool allowJoystickOverTouchPad;
public RadiusBase radiusBase;
public float radiusBaseValue;
public ETCAxis axisX;
public ETCAxis axisY;
public RectTransform thumb;
public JoystickArea joystickArea;
public RectTransform userArea;
public bool isTurnAndMove = false;
public float tmSpeed = 10;
public float tmAdditionnalRotation = 0;
public AnimationCurve tmMoveCurve;
public bool tmLockInJump = false;
private Vector3 tmLastMove;
#endregion
#region Private members
private Vector2 thumbPosition;
private bool isDynamicActif;
private Vector2 tmpAxis;
private Vector2 OldTmpAxis;
private bool isOnTouch;
#endregion
#region Joystick behavior option
[SerializeField]
private bool isNoReturnThumb;
public bool IsNoReturnThumb {
get {
return isNoReturnThumb;
}
set {
isNoReturnThumb = value;
}
}
private Vector2 noReturnPosition;
private Vector2 noReturnOffset;
[SerializeField]
private bool isNoOffsetThumb;
public bool IsNoOffsetThumb {
get {
return isNoOffsetThumb;
}
set {
isNoOffsetThumb = value;
}
}
#endregion
#region Inspector
#endregion
#endregion
#region Constructor
public ETCJoystick(){
joystickType = JoystickType.Static;
allowJoystickOverTouchPad = false;
radiusBase = RadiusBase.Width;
axisX = new ETCAxis("Horizontal");
axisY = new ETCAxis("Vertical");
_visible = true;
_activated = true;
joystickArea = JoystickArea.FullScreen;
isDynamicActif = false;
isOnDrag = false;
isOnTouch = false;
axisX.unityAxis = "Horizontal";
axisY.unityAxis = "Vertical";
enableKeySimulation = true;
isNoReturnThumb = false;
showPSInspector = false;
showAxesInspector = false;
showEventInspector = false;
showSpriteInspector = false;
}
#endregion
#region Monobehaviours Callback
protected override void Awake (){
base.Awake ();
if (joystickType == JoystickType.Dynamic){
this.rectTransform().anchorMin = new Vector2(0.5f,0.5f);
this.rectTransform().anchorMax = new Vector2(0.5f,0.5f);
this.rectTransform().SetAsLastSibling();
visible = false;
}
if (allowSimulationStandalone && enableKeySimulation && !Application.isEditor && joystickType!=JoystickType.Dynamic){
SetVisible(visibleOnStandalone);
}
}
public override void Start(){
axisX.InitAxis();
axisY.InitAxis();
if (enableCamera){
InitCameraLookAt();
}
tmpAxis = Vector2.zero;
OldTmpAxis = Vector2.zero;
noReturnPosition = thumb.position;
pointId = -1;
if (joystickType == JoystickType.Dynamic){
visible = false;
}
base.Start();
// Init Camera position
if (enableCamera && cameraMode == CameraMode.SmoothFollow){
if (cameraTransform && cameraLookAt){
cameraTransform.position = cameraLookAt.TransformPoint( new Vector3(0,followHeight,-followDistance));
cameraTransform.LookAt( cameraLookAt);
}
}
if (enableCamera && cameraMode == CameraMode.Follow){
if (cameraTransform && cameraLookAt){
cameraTransform.position = cameraLookAt.position + followOffset;
cameraTransform.LookAt( cameraLookAt.position);
}
}
}
public override void Update (){
base.Update ();
#region dynamic joystick
if (joystickType == JoystickType.Dynamic && !_visible && _activated){
Vector2 localPosition = Vector2.zero;
Vector2 screenPosition = Vector2.zero;
if (isTouchOverJoystickArea(ref localPosition, ref screenPosition)){
GameObject overGO = GetFirstUIElement( screenPosition);
if (overGO == null || (allowJoystickOverTouchPad && overGO.GetComponent<ETCTouchPad>()) || (overGO != null && overGO.GetComponent<ETCArea>() ) ) {
cachedRectTransform.anchoredPosition = localPosition;
visible = true;
}
}
}
if (joystickType == JoystickType.Dynamic && _visible){
if (GetTouchCount()==0){
visible = false;
}
}
#endregion
}
public override void LateUpdate (){
if (enableCamera && !cameraLookAt ){
InitCameraLookAt();
}
base.LateUpdate ();
}
private void InitCameraLookAt(){
if (cameraTargetMode == CameraTargetMode.FromDirectActionAxisX){
cameraLookAt = axisX.directTransform;
}
else if (cameraTargetMode == CameraTargetMode.FromDirectActionAxisY){
cameraLookAt = axisY.directTransform;
if (isTurnAndMove){
cameraLookAt = axisX.directTransform;
}
}
else if (cameraTargetMode == CameraTargetMode.LinkOnTag){
GameObject tmpobj = GameObject.FindGameObjectWithTag(camTargetTag);
if (tmpobj){
cameraLookAt = tmpobj.transform;
}
}
if (cameraLookAt)
cameraLookAtCC = cameraLookAt.GetComponent<CharacterController>();
}
protected override void UpdateControlState (){
if (_visible){
UpdateJoystick();
}
else{
if (joystickType == JoystickType.Dynamic){
OnUp( false);
}
}
}
#endregion
#region UI Callback
public void OnPointerEnter(PointerEventData eventData){
if (joystickType == JoystickType.Dynamic && !isDynamicActif && _activated && pointId==-1){
eventData.pointerDrag = gameObject;
eventData.pointerPress = gameObject;
isDynamicActif = true;
pointId = eventData.pointerId;
}
if (joystickType == JoystickType.Dynamic && !eventData.eligibleForClick){
OnPointerUp( eventData );
}
}
public void OnPointerDown(PointerEventData eventData){
onTouchStart.Invoke();
pointId = eventData.pointerId;
if (isNoOffsetThumb){
OnDrag( eventData);
}
}
public void OnBeginDrag(PointerEventData eventData){
}
public void OnDrag(PointerEventData eventData){
if (pointId == eventData.pointerId){
isOnDrag = true;
isOnTouch = true;
float radius = GetRadius();
if (!isNoReturnThumb){
thumbPosition = (eventData.position - eventData.pressPosition);// / (cachedRootCanvas.rectTransform().localScale.x ) ;
}
else{
thumbPosition =((eventData.position - noReturnPosition) /cachedRootCanvas.rectTransform().localScale.x) + noReturnOffset;
}
if (isNoOffsetThumb){
thumbPosition = (eventData.position - (Vector2)cachedRectTransform.position) / cachedRootCanvas.rectTransform().localScale.x;
}
thumbPosition.x = Mathf.FloorToInt( thumbPosition.x);
thumbPosition.y = Mathf.FloorToInt( thumbPosition.y);
if (!axisX.enable){
thumbPosition.x=0;
}
if (!axisY.enable){
thumbPosition.y=0;
}
if (thumbPosition.magnitude > radius){
if (!isNoReturnThumb){
thumbPosition = thumbPosition.normalized * radius ;
}
else{
thumbPosition = thumbPosition.normalized * radius;
}
}
thumb.anchoredPosition = thumbPosition;
}
}
public void OnPointerUp (PointerEventData eventData){
if (pointId == eventData.pointerId){
OnUp();
}
}
private void OnUp(bool real=true){
isOnDrag = false;
isOnTouch = false;
if (isNoReturnThumb){
noReturnPosition = thumb.position;
noReturnOffset = thumbPosition;
}
if (!isNoReturnThumb){
thumbPosition = Vector2.zero;
thumb.anchoredPosition = Vector2.zero;
axisX.axisState = ETCAxis.AxisState.None;
axisY.axisState = ETCAxis.AxisState.None;
}
if (!axisX.isEnertia && !axisY.isEnertia){
axisX.ResetAxis();
axisY.ResetAxis();
tmpAxis = Vector2.zero;
OldTmpAxis = Vector2.zero;
if (real){
onMoveEnd.Invoke();
}
}
if (joystickType == JoystickType.Dynamic){
visible = false;
isDynamicActif = false;
}
pointId=-1;
if (real){
onTouchUp.Invoke();
}
}
#endregion
#region Joystick Update
protected override void DoActionBeforeEndOfFrame (){
axisX.DoGravity();
axisY.DoGravity();
}
private void UpdateJoystick(){
#region Unity axes
if (enableKeySimulation && !isOnTouch && _activated && _visible ){
float x = Input.GetAxis(axisX.unityAxis);
float y= Input.GetAxis(axisY.unityAxis);
if (!isNoReturnThumb){
thumb.localPosition = Vector2.zero;
}
isOnDrag = false;
if (x!=0){
isOnDrag = true;
thumb.localPosition = new Vector2(GetRadius()*x, thumb.localPosition.y);
}
if (y!=0){
isOnDrag = true;
thumb.localPosition = new Vector2(thumb.localPosition.x,GetRadius()*y );
}
thumbPosition = thumb.localPosition;
}
#endregion
// Computejoystick value
OldTmpAxis.x = axisX.axisValue;
OldTmpAxis.y = axisY.axisValue;
tmpAxis = thumbPosition / GetRadius();
axisX.UpdateAxis( tmpAxis.x,isOnDrag, ETCBase.ControlType.Joystick,true);
axisY.UpdateAxis( tmpAxis.y,isOnDrag, ETCBase.ControlType.Joystick,true);
#region Move event
if ((axisX.axisValue!=0 || axisY.axisValue!=0 ) && OldTmpAxis == Vector2.zero){
onMoveStart.Invoke();
}
if (axisX.axisValue!=0 || axisY.axisValue!=0 ){
if (!isTurnAndMove){
// X axis
if( axisX.actionOn == ETCAxis.ActionOn.Down && (axisX.axisState == ETCAxis.AxisState.DownLeft || axisX.axisState == ETCAxis.AxisState.DownRight)){
axisX.DoDirectAction();
}
else if (axisX.actionOn == ETCAxis.ActionOn.Press){
axisX.DoDirectAction();
}
// Y axis
if( axisY.actionOn == ETCAxis.ActionOn.Down && (axisY.axisState == ETCAxis.AxisState.DownUp || axisY.axisState == ETCAxis.AxisState.DownDown)){
axisY.DoDirectAction();
}
else if (axisY.actionOn == ETCAxis.ActionOn.Press){
axisY.DoDirectAction();
}
}
else{
DoTurnAndMove();
}
onMove.Invoke( new Vector2(axisX.axisValue,axisY.axisValue));
onMoveSpeed.Invoke( new Vector2(axisX.axisSpeedValue,axisY.axisSpeedValue));
}
else if (axisX.axisValue==0 && axisY.axisValue==0 && OldTmpAxis!=Vector2.zero) {
onMoveEnd.Invoke();
}
if (!isTurnAndMove){
if (axisX.axisValue==0 && axisX.directCharacterController ){
if (!axisX.directCharacterController.isGrounded && axisX.isLockinJump)
axisX.DoDirectAction();
}
if (axisY.axisValue==0 && axisY.directCharacterController ){
if (!axisY.directCharacterController.isGrounded && axisY.isLockinJump)
axisY.DoDirectAction();
}
}
else{
if ((axisX.axisValue==0 && axisY.axisValue==0) && axisX.directCharacterController ){
if (!axisX.directCharacterController.isGrounded && tmLockInJump)
DoTurnAndMove();
}
}
#endregion
#region Down & press event
float coef =1;
if (axisX.invertedAxis) coef = -1;
if (Mathf.Abs(OldTmpAxis.x)< axisX.axisThreshold && Mathf.Abs(axisX.axisValue)>=axisX.axisThreshold){
if (axisX.axisValue*coef >0){
axisX.axisState = ETCAxis.AxisState.DownRight;
OnDownRight.Invoke();
}
else if (axisX.axisValue*coef<0){
axisX.axisState = ETCAxis.AxisState.DownLeft;
OnDownLeft.Invoke();
}
else{
axisX.axisState = ETCAxis.AxisState.None;
}
}
else if (axisX.axisState!= ETCAxis.AxisState.None) {
if (axisX.axisValue*coef>0){
axisX.axisState = ETCAxis.AxisState.PressRight;
OnPressRight.Invoke();
}
else if (axisX.axisValue*coef<0){
axisX.axisState = ETCAxis.AxisState.PressLeft;
OnPressLeft.Invoke();
}
else{
axisX.axisState = ETCAxis.AxisState.None;
}
}
coef =1;
if (axisY.invertedAxis) coef = -1;
if (Mathf.Abs(OldTmpAxis.y)< axisY.axisThreshold && Mathf.Abs(axisY.axisValue)>=axisY.axisThreshold ){
if (axisY.axisValue*coef>0){
axisY.axisState = ETCAxis.AxisState.DownUp;
OnDownUp.Invoke();
}
else if (axisY.axisValue*coef<0){
axisY.axisState = ETCAxis.AxisState.DownDown;
OnDownDown.Invoke();
}
else{
axisY.axisState = ETCAxis.AxisState.None;
}
}
else if (axisY.axisState!= ETCAxis.AxisState.None) {
if (axisY.axisValue*coef>0){
axisY.axisState = ETCAxis.AxisState.PressUp;
OnPressUp.Invoke();
}
else if (axisY.axisValue*coef<0){
axisY.axisState = ETCAxis.AxisState.PressDown;
OnPressDown.Invoke();
}
else{
axisY.axisState = ETCAxis.AxisState.None;
}
}
#endregion
}
#endregion
#region Touch manager
private bool isTouchOverJoystickArea(ref Vector2 localPosition, ref Vector2 screenPosition){
bool touchOverArea = false;
bool doTest = false;
screenPosition = Vector2.zero;
int count = GetTouchCount();
int i=0;
while (i<count && !touchOverArea){
#if ((UNITY_ANDROID || UNITY_IOS || UNITY_WINRT || UNITY_BLACKBERRY) && !UNITY_EDITOR)
if (Input.GetTouch(i).phase == TouchPhase.Began){
screenPosition = Input.GetTouch(i).position;
doTest = true;
}
#else
if (Input.GetMouseButtonDown(0)){
screenPosition = Input.mousePosition;
doTest = true;
}
#endif
if (doTest && isScreenPointOverArea(screenPosition, ref localPosition) ){
touchOverArea = true;
}
i++;
}
return touchOverArea;
}
private bool isScreenPointOverArea(Vector2 screenPosition, ref Vector2 localPosition){
bool returnValue = false;
if (joystickArea != JoystickArea.UserDefined){
if (RectTransformUtility.ScreenPointToLocalPointInRectangle( cachedRootCanvas.rectTransform(),screenPosition,null,out localPosition)){
switch (joystickArea){
case JoystickArea.Left:
if (localPosition.x<0){
returnValue=true;
}
break;
case JoystickArea.Right:
if (localPosition.x>0){
returnValue = true;
}
break;
case JoystickArea.FullScreen:
returnValue = true;
break;
case JoystickArea.TopLeft:
if (localPosition.y>0 && localPosition.x<0){
returnValue = true;
}
break;
case JoystickArea.Top:
if (localPosition.y>0){
returnValue = true;
}
break;
case JoystickArea.TopRight:
if (localPosition.y>0 && localPosition.x>0){
returnValue=true;
}
break;
case JoystickArea.BottomLeft:
if (localPosition.y<0 && localPosition.x<0){
returnValue = true;
}
break;
case JoystickArea.Bottom:
if (localPosition.y<0){
returnValue = true;
}
break;
case JoystickArea.BottomRight:
if (localPosition.y<0 && localPosition.x>0){
returnValue = true;
}
break;
}
}
}
else{
if (RectTransformUtility.RectangleContainsScreenPoint( userArea, screenPosition, cachedRootCanvas.worldCamera )){
RectTransformUtility.ScreenPointToLocalPointInRectangle( cachedRootCanvas.rectTransform(),screenPosition,cachedRootCanvas.worldCamera,out localPosition);
returnValue = true;
}
}
return returnValue;
}
private int GetTouchCount(){
#if ((UNITY_ANDROID || UNITY_IOS || UNITY_WINRT || UNITY_BLACKBERRY) && !UNITY_EDITOR)
return Input.touchCount;
#else
if (Input.GetMouseButton(0) || Input.GetMouseButtonUp(0)){
return 1;
}
else{
return 0;
}
#endif
}
#endregion
#region Other private method
public float GetRadius(){
float radius =0;
switch (radiusBase){
case RadiusBase.Width:
radius = cachedRectTransform.sizeDelta.x * 0.5f;
break;
case RadiusBase.Height:
radius = cachedRectTransform.sizeDelta.y * 0.5f;
break;
case RadiusBase.UserDefined:
radius = radiusBaseValue;
break;
}
return radius;
}
protected override void SetActivated (){
GetComponent<CanvasGroup>().blocksRaycasts = _activated;
if (!_activated){
OnUp(false);
}
}
protected override void SetVisible (bool visible=true){
bool localVisible = _visible;
if (!visible){
localVisible = visible;
}
GetComponent<Image>().enabled = localVisible;
thumb.GetComponent<Image>().enabled = localVisible;
GetComponent<CanvasGroup>().blocksRaycasts = _activated;
}
#endregion
private void DoTurnAndMove(){
float angle =Mathf.Atan2( axisX.axisValue,axisY.axisValue ) * Mathf.Rad2Deg;
float speed = tmMoveCurve.Evaluate( new Vector2(axisX.axisValue,axisY.axisValue).magnitude) * tmSpeed;
if (axisX.directTransform != null){
axisX.directTransform.rotation = Quaternion.Euler(new Vector3(0, angle + tmAdditionnalRotation,0));
if (axisX.directCharacterController != null){
if (axisX.directCharacterController.isGrounded || !tmLockInJump){
Vector3 move = axisX.directCharacterController.transform.TransformDirection(Vector3.forward) * speed;
axisX.directCharacterController.Move(move* Time.deltaTime);
tmLastMove = move;
}
else{
axisX.directCharacterController.Move(tmLastMove* Time.deltaTime);
}
}
else{
axisX.directTransform.Translate(Vector3.forward * speed * Time.deltaTime,Space.Self);
}
}
}
public void InitCurve(){
axisX.InitDeadCurve();
axisY.InitDeadCurve();
InitTurnMoveCurve();
}
public void InitTurnMoveCurve(){
tmMoveCurve = AnimationCurve.EaseInOut(0,0,1,1);
tmMoveCurve.postWrapMode = WrapMode.PingPong;
tmMoveCurve.preWrapMode = WrapMode.PingPong;
}
}