Unity 花活小剧场 - 通过ScrollRect可以做摇杆?

实现思路:

  • 利用Scroll Rect组件的Elastic MovementType实现Handle的回弹居中;
  • 重写SetContentAnchoredPosition函数,限制Handle的拖动范围;
  • 重写OnDragOnEndDrag函数,记录拖动形成的Direction方向;
  • 添加回调函数,实现摇杆驱动。

Elastic MovementType

添加两个圆形Image,中间的小圆就是摇杆Handle,将其拖拽到Scroll Rect组件中的Content属性中,如图所示:
Scroll Rect
Movement Type使用默认Elastic类型,该属性帮忙我们可以实现Handle的回弹居中,如图所示:

回弹居中

限制Handle的拖动范围

创建脚本SimpleJoystick,继承ScrollRect类,通过Override虚函数SetContentAnchoredPosition来限制Handle的可拖拽范围:

using UnityEngine;
using UnityEngine.UI;

public class SimpleJoystick : ScrollRect
{
    
    
    protected override void SetContentAnchoredPosition(Vector2 position)
    {
    
    
        //base.SetContentAnchoredPosition(position);

        if (position != content.anchoredPosition)
        {
    
    
        	//大圆的半径
            float radius = (transform as RectTransform).rect.height * .5f;
            //限制拖拽范围在半径内
            content.anchoredPosition = position.magnitude <= radius ? position : position.normalized * radius;
            UpdateBounds();
        }
    }
}

拖拽限制

记录拖拽形成的方向

声明Vecotor3类型变量,记录拖拽形成的方向,在拖拽过程中记录,在结束拖拽时重置为Vector3.Zero:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class SimpleJoystick : ScrollRect
{
    
    
    private Vector3 direction;

    protected override void SetContentAnchoredPosition(Vector2 position)
    {
    
    
        //base.SetContentAnchoredPosition(position);

        if (position != content.anchoredPosition)
        {
    
    
            float radius = (transform as RectTransform).rect.height * .5f;
            content.anchoredPosition = position.magnitude <= radius ? position : position.normalized * radius;
            UpdateBounds();
        }
    }

    public override void OnDrag(PointerEventData eventData)
    {
    
    
        base.OnDrag(eventData);
        
        direction = new Vector3(content.anchoredPosition.x, 0f, content.anchoredPosition.y);
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
    
    
        base.OnEndDrag(eventData);

        direction = Vector3.zero;
    }
}

添加回调函数

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class SimpleJoystick : ScrollRect
{
    
    
    public UnityAction<Vector3> onDrag;

    private Vector3 direction;

    protected override void SetContentAnchoredPosition(Vector2 position)
    {
    
    
        //base.SetContentAnchoredPosition(position);

        if (position != content.anchoredPosition)
        {
    
    
            float radius = (transform as RectTransform).rect.height * .5f;
            content.anchoredPosition = position.magnitude <= radius ? position : position.normalized * radius;
            UpdateBounds();
        }
    }


    public override void OnDrag(PointerEventData eventData)
    {
    
    
        base.OnDrag(eventData);
        
        direction = new Vector3(content.anchoredPosition.x, 0f, content.anchoredPosition.y);
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
    
    
        base.OnEndDrag(eventData);

        direction = Vector3.zero;
    }

    private void Update()
    {
    
    
        if (content.anchoredPosition != Vector2.zero)
        {
    
    
            onDrag?.Invoke(direction);
        }
    }
}

Example示例:

using UnityEngine;

public class Example : MonoBehaviour
{
    
    
    [SerializeField] private Rigidbody rb;
    [SerializeField] private SimpleJoystick joystick;

    private void Start()
    {
    
    
        joystick.onDrag += OnJoystickDrag;
    }

    private void OnJoystickDrag(Vector3 direction)
    {
    
    
        rb.velocity += direction.normalized * Time.deltaTime * 15f;
        if (direction != Vector3.zero)
        {
    
    
            rb.transform.rotation = Quaternion.LookRotation(direction);
        }
    }
}

摇杆驱动

猜你喜欢

转载自blog.csdn.net/qq_42139931/article/details/128922491
今日推荐