跳到正文
Qiita · Unity 开发社区· 来源· shin270080·· 2 小时前AI 评分15

Unity Input System 实现鼠标与触摸通用的拖拽操作

Unity Input Systemでマウス・タッチ共通のドラッグ操作を実装する

正文 · AI 翻译

0

转到点赞用户列表

0

在 X (Twitter) 上分享

在 Facebook 上分享

添加到 Hatena Bookmark

删除文章

已删除的文章无法恢复。

本文的草稿也会被删除。

您确定要删除这篇文章吗?

在Unity Input System中实现鼠标与触摸通用的拖拽操作

为了避免面向智能手机的游戏出现“在PC上可以拖拽,但在真机上操作不稳定”的问题,我们将Pointer输入统一为一种。在Unity 6中可以使用Input System 1.17。

方針

  • 将鼠标和触摸作为Pointer进行处理
  • 按下瞬间不开始拖拽
  • 超过一定距离后进入拖拽状态
  • 根据释放的位置进行吸附或还原

输入操作

将Point分配给<Pointer>/position,将Press分配给<Pointer>/press。

実装例

using UnityEngine;
using UnityEngine.InputSystem;

public sealed class PointerDragController : MonoBehaviour
{
    [SerializeField] private InputActionReference pointAction;
    [SerializeField] private InputActionReference pressAction;
    [SerializeField] private Camera targetCamera;
    [SerializeField] private float dragThreshold = 12f;

    private Vector2 pressScreenPosition;
    private Vector3 startWorldPosition;
    private bool pressed;
    private bool dragging;

    private void OnEnable()
    {
        pointAction.action.Enable();
        pressAction.action.Enable();
        pressAction.action.performed += OnPress;
        pressAction.action.canceled += OnRelease;
    }

    private void OnDisable()
    {
        pressAction.action.performed -= OnPress;
        pressAction.action.canceled -= OnRelease;
        pointAction.action.Disable();
        pressAction.action.Disable();
    }

    private void Update()
    {
        if (!pressed) return;

        Vector2 current = pointAction.action.ReadValue<Vector2>();

        if (!dragging &&
            Vector2.Distance(pressScreenPosition, current) >= dragThreshold)
        {
            dragging = true;
        }

        if (!dragging) return;

        Vector3 world = ScreenToWorld(current);
        transform.position = new Vector3(
            world.x,
            world.y,
            startWorldPosition.z
        );
    }

    private void OnPress(InputAction.CallbackContext context)
    {
        pressed = true;
        dragging = false;
        pressScreenPosition = pointAction.action.ReadValue<Vector2>();
        startWorldPosition = transform.position;
    }

    private void OnRelease(InputAction.CallbackContext context)
    {
        if (dragging)
        {
            TrySnapOrReturn();
        }

        pressed = false;
        dragging = false;
    }

    private Vector3 ScreenToWorld(Vector2 screen)
    {
        Vector3 p = new(screen.x, screen.y,
            Mathf.Abs(targetCamera.transform.position.z -
                      transform.position.z));
        return targetCamera.ScreenToWorldPoint(p);
    }

    private void TrySnapOrReturn()
    {
        Collider2D hit = Physics2D.OverlapPoint(transform.position);

        if (hit != null && hit.TryGetComponent(out SnapTarget target))
        {
            transform.position = target.SnapPosition;
            return;
        }

        transform.position = startWorldPosition;
    }
}

吸附目标拆分为小型组件。

using UnityEngine;

public sealed class SnapTarget : MonoBehaviour
{
    public Vector3 SnapPosition => transform.position;
}

减少误操作的要点

  1. dragThreshold放入
  2. 不将UI上的指针传递给游戏端
  3. 为吸附判定留出余量
  4. 成功时返回声音或小型动画
  5. 针对各设备确认安全区域与分辨率

总结

与按输入设备分别处理相比,以 Pointer 为单位构建状态转换会更易于管理。
明确“按下→移动一定距离→拖拽→释放”的流程,也能减少点击与拖拽的误判。

官方文档: https://docs.unity3d.com/ja/current/Manual/com.unity.inputsystem.html

长洲港町电气工事也在进行游戏和应用程序的制作。

0

查看点赞的用户列表

0

注册为新用户并更便捷地使用 Qiita

  1. 获取符合您需求的文章
  2. 您可以高效地读取有用信息
  3. 您可以使用深色主题

注册后可以做什么

0

前往查看喜欢您的用户列表

0

删除文章

已删除的文章无法恢复。

本文的草稿也将被删除。

您确定要删除这篇文章吗?

来源:Qiita · Unity 开发社区 · qiita.com