Unity小实用八-使用input system进行单指/双指的手势操作

1、在package manager中先安装Input system 包。

2、安装完成之后,创建input action。创建单手指操作,创建一个获取单手指位置的action,一个获取单手指交互的action。

3、创建双手指的操作,创建一个获取第一个手指位置的action,一个获取第二个手指位置的action,一个获取第二个手指交互的action。

4、创建InputManager.cs脚本,用来管理所有的操作信息。

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;

[DefaultExecutionOrder(-1)]
public class InputManager : MonoBehaviourSingleton<InputManager>
{
    public Action<Vector2, Vector2> pinchStarted;
    public Action<Vector2, Vector2> pinchChanged;
    public Action<Vector2, Vector2> pinchEnd;

    public Action<Vector2, float> swipeStarted;
    public Action<Vector2, float> swipeChanged;
    public Action<Vector2, float> swipeEnd;

    private InputControls _inputControl;
    private Coroutine _swipeCoroutine;
    private Coroutine _pinchCoroutine;

    private void Awake()
    {
        _inputControl = new InputControls();
    }

    private void OnEnable()
    {
        _inputControl.Enable();
    }

    private void OnDisable()
    {
        _inputControl.Disable();
    }

    // Start is called before the first frame update
    void Start()
    {
        _inputControl.Touch.SecondaryTouchContact.started += _ => PinchStart();
        _inputControl.Touch.SecondaryTouchContact.canceled += _ => PinchEnd();

        _inputControl.Touch.PrimaryContact.started += SwipeStart;
        _inputControl.Touch.PrimaryContact.canceled += SwipeEnd;
    }

    private void SwipeStart(InputAction.CallbackContext ctx)
    {
        swipeStarted?.Invoke(_inputControl.Touch.PrimaryPosition.ReadValue<Vector2>(), (float)ctx.startTime);
        _swipeCoroutine = StartCoroutine(SwipeDetection(ctx));
    }

    private void SwipeEnd(InputAction.CallbackContext ctx)
    {
        swipeEnd?.Invoke(_inputControl.Touch.PrimaryPosition.ReadValue<Vector2>(), (float)ctx.time);
        StopCoroutine(_swipeCoroutine);
    }

    IEnumerator SwipeDetection(InputAction.CallbackContext ctx)
    {
        while (true)
        {
            if (Input.touchCount > 1)
            {
                break;
            }

            swipeChanged?.Invoke(_inputControl.Touch.PrimaryPosition.ReadValue<Vector2>(), (float)ctx.time);

            yield return null;
        }
    }

    private void PinchStart()
    {
        pinchStarted?.Invoke(_inputControl.Touch.PrimaryFingerPosition.ReadValue<Vector2>(), _inputControl.Touch.SecondaryFingerPosition.ReadValue<Vector2>());
        _pinchCoroutine = StartCoroutine(PinchDetection());
    }

    private void PinchEnd()
    {
        pinchEnd?.Invoke(_inputControl.Touch.PrimaryFingerPosition.ReadValue<Vector2>(), _inputControl.Touch.SecondaryFingerPosition.ReadValue<Vector2>());
        StopCoroutine(_pinchCoroutine);
    }

    IEnumerator PinchDetection()
    {
        while (true)
        {
            if(Input.touchCount == 2)
            {
                pinchChanged?.Invoke(_inputControl.Touch.PrimaryFingerPosition.ReadValue<Vector2>(), _inputControl.Touch.SecondaryFingerPosition.ReadValue<Vector2>());
            }

            yield return null;
        }
    }
}

5、在InputManger中,所有的手指触发操作都会有回调,创建单手指滑动的操作,让相机沿着正方体进行旋转。

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

public class SwipeDetection : MonoBehaviour
{
    [SerializeField]
    private Camera mainCamera;
    [SerializeField]
    private float minDistance = 4f;
    [SerializeField]
    float sensitivity = 20f;
    [SerializeField]
    private GameObject targetAnchor;

    private InputManager _inputManager;
    private float _startTime;
    private float _endTime;
    private Vector2 _startPosition;
    private Vector2 _endPosition;
    private Vector2 _previousPosition;

    private void Awake()
    {
        _inputManager = InputManager.Instance;
    }

    private void OnEnable()
    {
        _inputManager.swipeStarted += OnSwipeStarted;
        _inputManager.swipeEnd += OnSwipeEnd;
        _inputManager.swipeChanged += OnSwipeChanged;
    }

    private void OnDisable()
    {
        _inputManager.swipeStarted -= OnSwipeStarted;
        _inputManager.swipeEnd -= OnSwipeEnd;
        _inputManager.swipeChanged -= OnSwipeChanged;
    }

    private void OnSwipeStarted(Vector2 position, float time)
    {
        _startPosition = position;
        _previousPosition = position;
        _startTime = time;
    }

    private void OnSwipeEnd(Vector2 position, float time)
    {
        _endPosition = position;
        _endTime = time;

        Debug.DrawLine(_startPosition, _endPosition, Color.red, 5f);
    }

    private void OnSwipeChanged(Vector2 position, float time)
    {
        Vector2 curPosition = position;

        if(Vector2.Distance(curPosition, _previousPosition) < minDistance)
        {
            return;
        }

        float angle = Vector2.Angle(curPosition - _startPosition, Vector2.up);

        if(angle > 45.0 && angle < 135.0)
        {
            float x = (curPosition.x - _previousPosition.x) / Screen.width * sensitivity;
            mainCamera.transform.RotateAround(targetAnchor.transform.position, Vector3.up, x);
        } else
        {
            float y = (curPosition.y - _previousPosition.y) / Screen.height * sensitivity;
            mainCamera.transform.RotateAround(targetAnchor.transform.position, transform.right, -y);
        }

        _previousPosition = curPosition;
    }
}

6、Unity提供了RotateAround(targetAnchor.transform.position, Vector3.up, x);函数可以沿着某个物体旋转。我们也可以自己实现这个函数。

void MyRotateAround(Vector3 center, Vector3 axis, float angle)
 {
        Vector3 pos = transform.position;
        Quaternion rot = Quaternion.AngleAxis(angle, axis);
        Vector3 dir = pos - center; //计算从圆心指向摄像头的朝向向量
        dir = rot * dir;            //旋转此向量
        transform.position = center + dir;//移动摄像机位置
        var myrot = transform.rotation;
        //transform.rotation *= Quaternion.Inverse(myrot) * rot *myrot;//设置角度另一种方法
        transform.rotation = rot * myrot; //设置角度
 }

7、双手指操作,相机沿着正方体的方向进行拉近拉远的操作。

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

public class PinchDetection : MonoBehaviour
{
    [SerializeField]
    private Camera mainCamera;
    [SerializeField]
    private float cameraSpeed = 4f;
    [SerializeField]
    private GameObject targetAnchor;

    private InputManager _inputManager;
    private float _previousDistance;

    private void Awake()
    {
        _inputManager = InputManager.Instance;
    }

    private void OnEnable()
    {
        _inputManager.pinchStarted += OnPinchStarted;
        _inputManager.pinchChanged += OnPinchChanged;
    }

    private void OnDisable()
    {
        _inputManager.pinchStarted -= OnPinchStarted;
        _inputManager.pinchChanged -= OnPinchChanged;
    }

    public void OnPinchStarted(Vector2 position1, Vector2 position2)
    {
        _previousDistance = Vector2.Distance(position1, position2);
    }

    public void OnPinchChanged(Vector2 position1, Vector2 position2)
    {
        float distance = Vector2.Distance(position1, position2);
        if (distance > _previousDistance)
        {
            Vector3 forward = targetAnchor.transform.position - mainCamera.transform.position;

            mainCamera.transform.Translate(forward.normalized * Time.deltaTime * cameraSpeed, Space.World);
        }
        else
        {
            Vector3 forward = mainCamera.transform.position - targetAnchor.transform.position;

            mainCamera.transform.Translate(forward.normalized * Time.deltaTime * cameraSpeed, Space.World);
        }

        _previousDistance = distance;
    }
}

8、脚本都已经就位,我们就在Unity操作界面上进行绑定。

9、在PC端我们先调试一下单手指的操作。

10、最后在手机上展示一下我们的成功。

案例下载地址:

https://download.csdn.net/download/grace_yi/20559035?spm=1001.2014.3001.5501

参考文献:

https://www.cnblogs.com/tangzhenqiang/p/8966882.html

https://www.cnblogs.com/lichuangblog/p/7967307.html

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XR风云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值