iOS対応

【Unity×iOS】ピンチイン・アウトを実装する方法|ズーム対応完全ガイド

スマホアプリやゲームでマップの拡大縮小、カメラズーム、UIスケール調整などに欠かせない「ピンチイン・ピンチアウト(二本指ズーム)」。UnityとiOS環境での実装パターンを押さえておけば、さまざまなシーンに対応可能です。この記事では、標準Input/新Input System(EnhancedTouch)/UIイベント/iOSネイティブプラグイン の4つの手法を、コピペで使えるサンプルコード付きで解説します。

この記事で分かること

  1. Unity標準Input.touchesを使ったピンチ検出の基本
  2. コピペOKの汎用PinchZoomスクリプト
  3. 新Input System+EnhancedTouchでの高精度マルチタッチズーム
  4. UIイベント(EventTrigger / IPointerDownHandler)でのズーム対応
  5. (応用)iOSネイティブのUIPinchGestureRecognizerプラグイン

Unity標準Inputでピンチイン・アウトを検出する

二本指の距離差からズーム量を計算

  • zoomSpeed:調整用倍率
  • minFOV/maxFOV:ズーム範囲
void Update()
{
    if (Input.touchCount != 2) return;

    Touch t0 = Input.GetTouch(0);
    Touch t1 = Input.GetTouch(1);

    // 前フレームの指の位置
    Vector2 prevPos0 = t0.position - t0.deltaPosition;
    Vector2 prevPos1 = t1.position - t1.deltaPosition;

    float prevDistance = Vector2.Distance(prevPos0, prevPos1);
    float currDistance = Vector2.Distance(t0.position, t1.position);

    // 距離の変化量:正ならピンチアウト、負ならピンチイン
    float delta = currDistance - prevDistance;

    // ズーム処理を呼び出し(例:カメラのField of Viewを調整)
    Camera.main.fieldOfView -= delta * zoomSpeed;
    Camera.main.fieldOfView = Mathf.Clamp(Camera.main.fieldOfView, minFOV, maxFOV);
}

汎用PinchZoomスクリプト(コピペOK)

  1. 任意のGameObjectにアタッチ
  2. インスペクタでzoomSpeed/minFOV/maxFOVを設定
  3. 実行して二本指でピンチイン・アウトを確認
using UnityEngine;

public class PinchZoom : MonoBehaviour
{
    [Header("ズーム設定")]
    public float zoomSpeed = 0.1f;
    public float minFOV    = 15f;
    public float maxFOV    = 90f;

    void Update()
    {
        if (Input.touchCount != 2) return;

        Touch t0 = Input.GetTouch(0);
        Touch t1 = Input.GetTouch(1);

        Vector2 prev0 = t0.position - t0.deltaPosition;
        Vector2 prev1 = t1.position - t1.deltaPosition;

        float prevDist = Vector2.Distance(prev0, prev1);
        float currDist = Vector2.Distance(t0.position, t1.position);
        float diff     = currDist - prevDist;

        // カメラのFOVを調整
        Camera cam = Camera.main;
        cam.fieldOfView = Mathf.Clamp(cam.fieldOfView - diff * zoomSpeed, minFOV, maxFOV);
    }
}

新Input System+EnhancedTouchでマルチタッチズーム

パッケージ有効化手順

  1. Edit → Project Settings → Player で Active Input Handling = Both を選択
  2. Window → Package Manager から Input System を導入
  3. スクリプト先頭でusing UnityEngine.InputSystem.EnhancedTouch;を追加

EnhancedTouch版PinchZoom

  • EnhancedTouchは指ごとの処理が簡単
  • 端末の解像度差を気にせずに距離を取得できる
using UnityEngine;
using UnityEngine.InputSystem.EnhancedTouch;
using TouchPhase = UnityEngine.InputSystem.TouchPhase;
using Finger     = UnityEngine.InputSystem.EnhancedTouch.Finger;

public class EnhancedPinchZoom : MonoBehaviour
{
    public float zoomSpeed = 0.2f;
    public float minFOV    = 15f;
    public float maxFOV    = 90f;

    void OnEnable()  => EnhancedTouchSupport.Enable();
    void OnDisable() => EnhancedTouchSupport.Disable();

    void Update()
    {
        var fingers = Touch.activeFingers;
        if (fingers.Count != 2) return;

        var f0 = fingers[0].currentTouch;
        var f1 = fingers.currentTouch;

        if (f0.phase == TouchPhase.Moved || f1.phase == TouchPhase.Moved)
        {
            float prevDist = Vector2.Distance(fingers[0].startScreenPosition, fingers.startScreenPosition);
            float currDist = Vector2.Distance(f0.screenPosition, f1.screenPosition);
            float diff     = currDist - prevDist;

            Camera cam = Camera.main;
            cam.fieldOfView = Mathf.Clamp(cam.fieldOfView - diff * zoomSpeed, minFOV, maxFOV);
        }
    }
}

UIイベントでズームを検出する

UIのCanvas上に置いた パネル などでズームを取りたい場合は、EventTriggerまたは IPointerDownHandler/IPointerUpHandlerで二本指の動きを追跡します。

  • UI要素のスケールを直接コントロール
  • ScrollRectなどと組み合わせるとパン&ズームUIが実現可能
using UnityEngine;
using UnityEngine.EventSystems;

public class UIPinchZoom : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    public float zoomSpeed = 0.1f;
    public float minScale  = 0.5f;
    public float maxScale  = 3f;

    RectTransform rt;
    float initialDist;
    Vector3 initialScale;
    bool   isPinching;

    void Awake() => rt = GetComponent<RectTransform>();

    public void OnPointerDown(PointerEventData e)
    {
        if (Input.touchCount == 2)
        {
            isPinching     = true;
            initialDist    = Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
            initialScale   = rt.localScale;
        }
    }

    public void OnPointerUp(PointerEventData e)
    {
        if (Input.touchCount < 2)
            isPinching = false;
    }

    void Update()
    {
        if (!isPinching || Input.touchCount != 2) return;

        float currDist = Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
        float diff     = (currDist - initialDist) * zoomSpeed;
        float scale    = Mathf.Clamp(initialScale.x + diff, minScale, maxScale);
        rt.localScale  = Vector3.one * scale;
    }
}

応用:iOSネイティブUIPinchGestureRecognizerプラグイン

 高度なジェスチャー情報(速度・中心点)を取得したい場合は、Objective-C++側で UIPinchGestureRecognizerを使い、Unityに通知する方法もあります。
 Unity側で [DllImport(“__Internal”)] private static extern void RegisterPinchHandler();を呼び出せば、iOS純正のジェスチャー認識が利用できます。

#import <UIKit/UIKit.h>

extern "C" {

void RegisterPinchHandler()
{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIPinchGestureRecognizer *pinch =
            [[UIPinchGestureRecognizer alloc] initWithTarget:[UnityAppController sharedInstance]
                                                      action:@selector(handlePinch:)];
        [[[UnityAppController sharedInstance] window] addGestureRecognizer:pinch];
    });
}
}

まとめ

手法メリット用途例
標準Input.touchesコピペOK・最小構成簡易カメラズーム
新Input System+EnhancedTouch高精度・マルチタッチ対応2本以上の複雑ジェスチャー
UIイベント(IPointer)UI要素単位のズームインタラクティブマップ、Photo Viewer
iOSネイティブ UIPinchGesture高度な速度・中心点情報取得可能ARアプリ、プロフェッショナルUI

用途に合わせて選択し、コピペで即導入してみてください!快適なズームUXを実現しましょう。