实现方式一:通过EventTrigger实现

  1. 自定义点击区域

  2. 制作按钮

  3. 在区域内点击触发事件

  4. 点击显示,抬起隐藏

  5. 旋钮的拖拽

点击触发事件如何实现?

有很多种实现方法,这里我采用了EventTrigger组件,通过拖拽函数的方式触发事件。

值得注意的是:拖拽的脚本必须是已经挂载在游戏对象上的脚本。

另外一种方法。

这里也可以采用通过拖拽获得EventTrigger,在通过代码去添加事件的方式来触发事件。

拖拽的难点

我没有使用拖拽函数,而是在Update中判断。

只有点击时拖拽才能够执行Update里面的内容,所以有一个布尔值CanDrag表示,按下才能够拖拽,抬起就不能够拖拽了。

private void Update()
{
    if (canControl)
        ControlJoyStick();
}

private void ControlJoyStick()
{
    Vector2 dir = Mouse.current.position.ReadValue()- clickPos;
    float moveRadius = dir.magnitude;
    // 最终呈现在屏幕上的大小 = 原来的大小 乘以 缩放比例
    float maxRaidus = joystickOutline.rect.width / 2 * canvasScaleX;
    moveRadius = Mathf.Min(moveRadius, maxRaidus);
    move = dir.normalized * moveRadius;
    joysticknob.position = clickPos + move;

    // 旧版输入系统
    //if(Input.GetMouseButtonUp(0))
    //    Hide();
    if(Mouse.current.leftButton.wasReleasedThisFrame)
    {
        Hide();
    }
}

完整代码

using UnityEngine;
using UnityEngine.InputSystem;

namespace DY
{
    /// <summary>
    /// 需要使用新输入系统
    /// 1. 允许玩家在自定义的区域内点击
    /// 2. 开始时隐藏,点击后显示
    /// 3. 控制旋钮
    /// 4. 返回一个方向,以控制玩家
    /// </summary>
    public class MobileJoystick : MonoBehaviour
    {
        [SerializeField] RectTransform joystickOutline;
        [SerializeField] RectTransform joysticknob;

        private float canvasScaleX;
        private Vector2 clickPos;
        private bool canControl;
        private Vector2 move;

        private void Start()
        {
            Hide();
            canvasScaleX = GetComponentInParent<Canvas>().GetComponent<RectTransform>().localScale.x;
        }

        private void Update()
        {
            if (canControl)
                ControlJoyStick();
        }

        private void ControlJoyStick()
        {
            Vector2 dir = Mouse.current.position.ReadValue()- clickPos;
            float moveRadius = dir.magnitude;
            // 最终呈现在屏幕上的大小 = 原来的大小 乘以 缩放比例
            float maxRaidus = joystickOutline.rect.width / 2 * canvasScaleX;
            moveRadius = Mathf.Min(moveRadius, maxRaidus);
            move = dir.normalized * moveRadius;
            joysticknob.position = clickPos + move;

            // 旧版输入系统
            //if(Input.GetMouseButtonUp(0))
            //    Hide();
            if(Mouse.current.leftButton.wasReleasedThisFrame)
            {
                Hide();
            }


        }

        private void Show()
        {
            joystickOutline.gameObject.SetActive(true);
            canControl = true;
        }

        private void Hide()
        {
            joystickOutline.gameObject.SetActive(false);
            canControl = false;
        }

        /// <summary>
        /// 在自定义的区域内点击,触发的回调函数
        /// </summary>
        public void ClickedOnJoystickZoneCallback()
        {
            clickPos = Mouse.current.position.ReadValue();
            joystickOutline.position = clickPos;
            Show();
        }

        public Vector3 GetMoveDir()
        {
            return move.normalized;
        }

    }
}

实现方式二:通过UGUI的事件函数实现

using UnityEngine;
using UnityEngine.EventSystems;

public class DragController : MonoBehaviour,
IPointerDownHandler, IPointerUpHandler,
IDragHandler
{
    public GameObject DragBar;
    public Transform Bar;

    //可移动区域的最远距离
    public float R;

    private void Start()
    {
        //DragBar.SetActive(false);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        //1.需要在UI上设定一个点击区域,点击后,摇杆出现,抬起后,摇杆消失
        //DragBar.SetActive(true);

        //2.根据点击位置移动整个摇杆
        Vector2 localPos;

        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            transform as RectTransform,//获取DragArea的Transform,底座在Area上
            eventData.position,//屏幕坐标系下触摸的点
            eventData.pressEventCamera,//触发事件的相机
            out localPos//获得的本地坐标系下的点
        );

        DragBar.transform.localPosition = localPos;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        //DragBar.SetActive(false);
        Bar.localPosition = Vector3.zero;
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector2 localPos;

        //3.拖拽时,将杆的位置进行移动
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            DragBar.transform as RectTransform,//获取DragBar的Transform,因为Bar是DragBar的子物体
            eventData.position,//屏幕坐标系下触摸的点
            eventData.pressEventCamera,//触发事件的相机
            out localPos//获得的本地坐标系下的点
        );
        //4.限制摇杆距离
        //越界了
        if (localPos.magnitude > R)
        {
            //拖拽点标准化*R
            localPos = localPos.normalized * R;
        }
        Bar.localPosition = localPos;
    }
}