【Unity】UGUI實現搖桿功能

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.EventSystems;

public class InputJoystick : MonoBehaviour
{
    //搖桿根節點
    [SerializeField] RectTransform joystickRoot;
    //搖桿節點
    [SerializeField] RectTransform joystickNode;
    //搖桿方向節點
    [SerializeField] RectTransform joystickDirection;

    //搖桿半徑
    [SerializeField] int joystickRadius = 200;
    //擡手搖桿復位速度
    [SerializeField, Range(0.01f, 1)] float revertPositionSpeed = 0.75f;
    //單擊判定時間範圍
    [SerializeField] float tapDuration = 0.1f;

    //搖桿事件回調
    public static Action OnJoystickMoveStart;
    public static Action<Vector2> OnJoystickMoving;
    public static Action OnJoystickMoveEnd;
    public static Action OnJoystickTap;

    //屏幕寬高
    private int screenWidth = Screen.width;
    private int screenHeight = Screen.height;

    //搖桿默認位置
    private Vector3 joystickDefaultPos;
    //按下時搖桿中心位置
    private Vector3 curJoystickOrigin;
    //按下時搖桿方向
    private Vector3 curJoystickDirection;

    private bool isInputing = false;        //是否按下搖桿
    private bool needToRevertRoot = false;  //根節點是否需要回位
    private bool needToRevertNode = false;  //遙感節點是否需要回位
    private bool isReadyToTap = false;      //是否判定單擊
    private bool isActived = true;          //是否激活搖桿

    //搖桿按下時間
    private float startInputTime;

    private void Awake()
    {
        joystickDefaultPos = joystickRoot.anchoredPosition;
    }
    private void Start()
    {
        joystickDirection.gameObject.SetActive(false);
    }

    private void Update()
    {
        if (!isActived)
            return;
        if (Input.GetMouseButtonDown(0))
        {
            if (IsRaycastUI())
                return;
            OnInputStart(Input.mousePosition);
            isInputing = true;
        }
        else if (Input.GetMouseButton(0))
        {
            if (isInputing)
                OnInputIng(Input.mousePosition);
        }
        else if (Input.GetMouseButtonUp(0))
        {
            if (isInputing)
            {
                OnInputEnd(Input.mousePosition);
                isInputing = false;
            }
        }
        else if (!isInputing)
        {
            if (needToRevertRoot)
            {
                RevertJoystickRootPos();
            }
            if (needToRevertNode)
            {
                RevertJoystickNodePos();
            }
        }
    }

    private bool IsRaycastUI()
    {
        //鼠標點擊事件
        return (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject());
    }

    //激活/取消激活 搖桿
    public void ActiveJoystick(bool active)
    {
        if (isActived == active)
            return;

        isActived = active;

        if (!isActived)
        {
            if (isInputing)
                OnJoystickMoveEnd?.Invoke();
        }

        joystickRoot.gameObject.SetActive(active);
        joystickRoot.anchoredPosition = joystickDefaultPos;
        joystickNode.localPosition = Vector3.zero;
    }

    #region --- 輸入回調 ---

    private void OnInputStart(Vector3 point)
    {
        curJoystickOrigin = point;

        startInputTime = Time.unscaledTime;
        isReadyToTap = true;

        Vector3 joystickPos = Vector3.zero;
        joystickPos.x = -0.5f * screenWidth + point.x;
        joystickPos.y = -0.5f * screenHeight + point.y;
        joystickRoot.anchoredPosition = joystickPos;
        joystickNode.localPosition = Vector3.zero;

        joystickDirection.gameObject.SetActive(true);

        OnJoystickMoveStart?.Invoke();
    }
    float tempLength;
    private void OnInputIng(Vector3 point)
    {
        tempLength = (point - curJoystickOrigin).magnitude;

        if (tempLength < 0.01f)
        {
            curJoystickDirection = Vector3.zero;
            OnJoystickMoving?.Invoke(curJoystickDirection);

            if (isReadyToTap)
            {
                if (Time.unscaledTime - startInputTime >= tapDuration)
                {
                    isReadyToTap = false;
                }
            }
        }
        else if (tempLength <= joystickRadius)
        {
            curJoystickDirection = (point - curJoystickOrigin).normalized * tempLength / joystickRadius;
            isReadyToTap = false;
        }
        else
        {
            curJoystickDirection = (point - curJoystickOrigin).normalized;
            isReadyToTap = false;
        }

        joystickNode.localPosition = curJoystickDirection * joystickRadius;
        if (curJoystickDirection == Vector3.zero)
            joystickDirection.up = Vector3.up;
        else
            joystickDirection.up = curJoystickDirection;

        OnJoystickMoving?.Invoke(curJoystickDirection);
    }
    private void OnInputEnd(Vector3 point)
    {
        curJoystickOrigin = joystickDefaultPos;

        needToRevertRoot = true;
        needToRevertNode = true;

        joystickDirection.gameObject.SetActive(false);

        if (isReadyToTap)
        {
            OnJoystickTap?.Invoke();
            isReadyToTap = false;
        }

        OnJoystickMoveEnd?.Invoke();
    }

    #endregion

    #region --- 搖桿復位 ---

    private void RevertJoystickRootPos()
    {
        if ((joystickRoot.position - joystickDefaultPos).sqrMagnitude > 0.1f)
        {
            joystickRoot.anchoredPosition = Vector3.Lerp(joystickRoot.anchoredPosition, joystickDefaultPos, revertPositionSpeed);
        }
        else
        {
            joystickRoot.anchoredPosition = joystickDefaultPos;
            needToRevertRoot = false;
        }
    }
    private void RevertJoystickNodePos()
    {
        if (joystickNode.localPosition.sqrMagnitude > 0.1f)
        {
            joystickNode.localPosition = Vector3.Lerp(joystickNode.localPosition, Vector3.zero, revertPositionSpeed);
        }
        else
        {
            joystickNode.localPosition = Vector3.zero;
            needToRevertNode = false;
        }
    }

    #endregion

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章