#pragma warning disable 0414 // private field assigned but not used. by kts123 2014.11.06 using UnityEngine; using System.Collections; using System; /// /// Allows dragging of the specified target object by mouse or touch, optionally limiting it to be within the UIPanel's clipped rectangle. /// [AddComponentMenu("NGUI/Interaction/Drag Object")] public class UIJoystick : MonoBehaviour { static UIJoystick[] joysticks; // A static collection of all joysticks static bool enumeratedJoysticks = false; /// /// Target object that will be dragged. /// public Transform target; public Vector3 scale = Vector3.one; public float radius = 40f; // the radius for the joystick to move public bool centerOnPress = true; Vector3 userInitTouchPos = Vector3.zero; //Joystick vars public bool normalize = false; // Normalize output after the dead-zone? public float fadeOutAlpha = 0.2f; public float fadeOutDelay = 1f; public UIWidget[] widgetsToFade; // UIWidgets that should fadeIn/Out when centerOnPress = true public Transform[] widgetsToCenter; // GameObjects to Center under users thumb when centerOnPress = true public float doubleTapTimeWindow = 0.5f; // time in Seconds to recognize a double tab public GameObject doubleTapMessageTarget; public string doubleTabMethodeName; public float damping = 1.0f; public Vector3 m_vPressPos = Vector3.zero; public Vector3 m_vOldPos = Vector2.zero; public Vector3 m_vCurrentPos = Vector2.zero; public GameObject RelayTarget = null; private UIJoystick RelayJoyStick = null; private Vector3 m_vSpringSpeed = Vector3.zero; public UIWidget m_pWidget = null; public DSEvent eventPressTouch = new DSEvent(); public DSEvent eventTouch = new DSEvent(); public DSEvent eventTouchDirection = new DSEvent(); public DSEvent eventStickDirection = new DSEvent(); public DSEvent eventTouchEnd = new DSEvent(); public GameObject[] m_arrDirection; // ------------------------------------------------------------ // 시스템 콜백 함수들 void Awake() { userInitTouchPos = target.position; SetRelayJoyStick(); } void Start() { userInitTouchPos = target.position; StartFadeOut(); } void Update() { if (false == enumeratedJoysticks) { // Collect all joysticks in the game, so we can relay finger latching messages joysticks = FindObjectsOfType(typeof(UIJoystick)) as UIJoystick[]; enumeratedJoysticks = true; } SetSpringStick(); } void OnEnable() { if (false == this.gameObject.activeInHierarchy) return; target.position = userInitTouchPos; SetPosToWidget(userInitTouchPos); m_vOldPos = Vector2.zero; m_vCurrentPos = Vector2.zero; StartFadeIn(); StartFadeOut(); RelayToEnable(); } void OnDisable() { target.position = userInitTouchPos; SetPosToWidget(userInitTouchPos); // ClearEvent(); } public void OnPress(bool bPressed) { if (target == null) return; if (true == bPressed) SetPressToOn(); else SetPressToOff(); } void OnDrag(Vector2 delta) { if (target == null) return; if (0.0f == delta.magnitude) return; m_vOldPos = m_vCurrentPos; m_vCurrentPos = GetPosToTouch(); // OldPos가 Zero(초기화 상태)이면 갑자기 조이스틱이 확 튀어가기 때문에 아래처럼 보완해줌 if (Vector3.zero == m_vOldPos) m_vOldPos = m_vCurrentPos; Vector3 vGap = Vector3.zero; // 현재 손가락 위치 기준 // vGap = GetConvertPosToTouchPos(m_vOldPos, m_vCurrentPos); // 처음 찍은 위치 기준 vGap = GetConvertPosToTouchPos(m_vPressPos, m_vCurrentPos); SetTargetDragging(vGap); SendEventToTouch(vGap); RelayToDrag(); } // ------------------------------------------------------------ // 초기화 및 종료 관련 함수들 public void ClearEvent() { eventTouch.Clear(); eventPressTouch.Clear(); eventTouchDirection.Clear(); eventStickDirection.Clear(); eventTouchEnd.Clear(); } // ------------------------------------------------------------ // 내부 유틸함수들 void SetPressToOn() { eventPressTouch.CallBack(this); StopAllCoroutines(); SendMsgToDoubleTabMethode(); TweenColorToFadeWidgets(Color.white, 1.0f, 0.1f, UITweener.Method.EaseIn); Vector3 vTouchPos = GetPosToTouch(); if (true == centerOnPress) { userInitTouchPos = vTouchPos; } m_vOldPos = vTouchPos; m_vCurrentPos = vTouchPos; m_vPressPos = vTouchPos; SetPosToWidget(userInitTouchPos); RelayToPressOn(); } void SetPressToOff() { // Release the finger control and set the joystick back to the default position // target.position = userInitTouchPos; SetPosToWidget(userInitTouchPos); m_vOldPos = Vector3.zero; m_vCurrentPos = Vector3.zero; m_vPressPos = Vector3.zero; StartFadeOut(); SendEventToEnd(); RelayToPressOff(); AllOffDirection(); } void AllOffDirection() { for (int i = 0; i < m_arrDirection.Length; ++i) { m_arrDirection[i].SetActive(false); } } void SetTargetDragging(Vector3 vGap) { target.localPosition = vGap; // Calculate the length. This involves a squareroot operation, // so it's slightly expensive. We re-use this length for multiple // things below to avoid doing the square-root more than one. Vector3 vLocalPos = target.localPosition; float fLength = vLocalPos.magnitude; // If the length of the vector is smaller than the deadZone radius, // set the position to the origin. if (fLength < 2) vLocalPos = Vector2.zero; else if (fLength > radius) vLocalPos = Vector2.ClampMagnitude(vLocalPos, radius); target.localPosition = widgetsToFade[1].transform.localPosition + vLocalPos; AllOffDirection(); /* float fAngle = Single.Physics.GetAngleToPositionZ(vLocalPos, Vector3.up); int iDirection = 0; if (fAngle < -90) iDirection = 2; else if (fAngle < 0) iDirection = 3; else if (fAngle > 90) iDirection = 1; if(m_arrDirection != null && m_arrDirection.Length > iDirection) m_arrDirection[iDirection].SetActive(true);*/ } void SetSpringStick() { if (false == IsZeroToTouchPos()) return; // 아래는 첫 클릭한 위치 기준으로 스프링 효과 // Vector3 vCenterPos = userInitTouchPos; // 아래는 조이스틱 이미지 기준으로 스프링 효과 Vector3 vCenterPos = widgetsToFade[1].transform.position; Vector3 vTargetPos = target.position; target.position = Single.Physics.CalculationSpring(vCenterPos, vTargetPos, ref m_vSpringSpeed, 1000.0f, 20.0f); RelayToSpringStick(); } Vector3 GetConvertPosToTouchPos(Vector3 vOldPos, Vector3 vPos) { Vector3 vOffset = (vPos - vOldPos); // 이동 값음 유아이 맨 루트에 보면 스케일만큼 작아진 기준으로 이동 값이 들어옴 // 그래서 그 스케일만큼 뻥튀기 해줘야 유아이상에서 똑같이 이동됨 if (vOffset.x != 0f || vOffset.y != 0f) { vOffset = target.InverseTransformDirection(vOffset); vOffset.Scale(scale); vOffset = target.TransformDirection(vOffset); } vOffset.z = 0.0f; return vOffset; } Vector3 GetTargetNormalize() { Vector3 vLocalPos = target.localPosition; if (false == normalize) return vLocalPos; else return vLocalPos / radius * Mathf.InverseLerp(radius, 0, 1); } Vector3 GetPosToTouch() { //set Joystick to finger touchposition Ray ray = UICamera.currentCamera.ScreenPointToRay(UICamera.lastEventPosition); Vector3 vTouchPos = ray.GetPoint(0.0f); vTouchPos.z = 0.0f; return vTouchPos; } void SetPosToWidget(Vector3 vPos) { foreach (Transform pWidget in widgetsToCenter) { pWidget.position = vPos; } } bool IsZeroToTouchPos() { return (Vector3.zero == m_vOldPos && Vector3.zero == m_vCurrentPos); } // ------------------------------------------------------------ // 릴레이 관련 void SetRelayJoyStick() { if (null == RelayTarget) return; RelayJoyStick = RelayTarget.GetComponent(); } bool IsRelay() { return (null != RelayJoyStick); } void RelayToEnable() { if (false == IsRelay()) return; RelayJoyStick.OnEnable(); } void RelayToPressOn() { if (false == IsRelay()) return; RelayJoyStick.SetRelayToPressOn(); } void RelayToPressOff() { if (false == IsRelay()) return; RelayJoyStick.SetRelayToPressOff(); } void RelayToDrag() { if (false == IsRelay()) return; RelayJoyStick.SetRelayToDrag(GetConvertPosToTouchPos(m_vOldPos, m_vCurrentPos)); } void RelayToSpringStick() { if (false == IsRelay()) return; RelayJoyStick.SetSpringStick(); } void SetRelayToPressOn() { StopAllCoroutines(); SendMsgToDoubleTabMethode(); TweenColorToFadeWidgets(Color.white, 1.0f, 0.1f, UITweener.Method.EaseIn); m_vOldPos = userInitTouchPos; m_vCurrentPos = userInitTouchPos; SetPosToWidget(userInitTouchPos); } void SetRelayToPressOff() { SetPressToOff(); } public void SetRelayToDrag(Vector3 vGap) { m_vOldPos = m_vCurrentPos; m_vCurrentPos = m_vOldPos + vGap; SetTargetDragging(vGap); SendEventToTouch(vGap); } // ------------------------------------------------------------ // 이벤트 관련 void SendEventToTouch(Vector2 vPos) { eventTouch.CallBack(this, vPos); eventTouchDirection.CallBack(this, vPos.normalized); //Vector3 vStickPos = target.localPosition; eventStickDirection.CallBack(this, vPos.normalized); } void SendEventToEnd() { eventTouchEnd.CallBack(this); } void SendMsgToDoubleTabMethode() { if (Time.deltaTime >= doubleTapTimeWindow) return; if (null == doubleTapMessageTarget) return; if ("" == doubleTabMethodeName) return; doubleTapMessageTarget.SendMessage(doubleTabMethodeName, SendMessageOptions.DontRequireReceiver); } // -------------------------------------------- // 등록된 위젯오브젝트들의 페이드 관련 void StartFadeIn() { if (false == this.gameObject.activeInHierarchy) return; StartCoroutine(FadeInJoystick()); } void StartFadeOut() { if (false == this.gameObject.activeInHierarchy) return; StartCoroutine(FadeOutJoystick()); } IEnumerator FadeInJoystick() { foreach (UIWidget widget in widgetsToFade) widget.color = GetAlphaColor(widget.color, fadeOutAlpha); yield return null; TweenColorToFadeWidgets(Color.white, 1.0f, 0.1f, UITweener.Method.EaseIn); } IEnumerator FadeOutJoystick() { yield return new WaitForSeconds(fadeOutDelay); TweenColorToFadeWidgets(null, fadeOutAlpha, 0.5f, UITweener.Method.EaseOut); } Color GetAlphaColor(Color pColor, float fAlpha) { pColor.a = fAlpha; return pColor; } void TweenColorToFadeWidgets(Color? pColor, float fAlpha, float fDuration, UITweener.Method eMethod) { // Add FadeIn Color without CenterOnPress Option[blueasa / 2014-11-08] foreach (UIWidget widget in widgetsToFade) { if (null == pColor) pColor = GetAlphaColor(widget.color, fAlpha); TweenColor.Begin(widget.gameObject, fDuration, pColor.Value).method = eMethod; } } public void SetAlpha(float fRValue) { if (null == m_pWidget) return; m_pWidget.alpha = fRValue; } }