0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

0
Posted at

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

スマホ向けゲームで「PCではドラッグできるのに、実機では操作が不安定」という問題を避けるため、Pointer入力を1本化します。Unity 6ではInput System 1.17が利用できます。

方針

  • マウスとタッチをPointerとして扱う
  • 押した瞬間にはドラッグを開始しない
  • 一定距離を超えたらドラッグ状態へ移行する
  • 離した位置に応じてスナップまたは元に戻す

Input Actions

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上のPointerをゲーム側に通さない
  3. スナップ判定に余裕を持たせる
  4. 成功時に音や小さなアニメーションを返す
  5. 端末ごとにSafe Areaと解像度を確認する

まとめ

入力デバイスごとに処理を分けるより、Pointer単位で状態遷移を作ると管理しやすくなります。
「押す→一定距離動く→ドラッグ→離す」を明示すると、クリックとドラッグの誤判定も減らせます。

公式ドキュメント: https://docs.unity3d.com/ja/current/Manual/com.unity.inputsystem.html

長洲港町電気工事では、ゲーム・アプリ制作にも取り組んでいます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?