スマホアプリやゲームでマップの拡大縮小、カメラズーム、UIスケール調整などに欠かせない「ピンチイン・ピンチアウト(二本指ズーム)」。UnityとiOS環境での実装パターンを押さえておけば、さまざまなシーンに対応可能です。この記事では、標準Input/新Input System(EnhancedTouch)/UIイベント/iOSネイティブプラグイン の4つの手法を、コピペで使えるサンプルコード付きで解説します。
この記事で分かること
- Unity標準Input.touchesを使ったピンチ検出の基本
- コピペOKの汎用PinchZoomスクリプト
- 新Input System+EnhancedTouchでの高精度マルチタッチズーム
- UIイベント(EventTrigger / IPointerDownHandler)でのズーム対応
- (応用)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)
- 任意のGameObjectにアタッチ
- インスペクタでzoomSpeed/minFOV/maxFOVを設定
- 実行して二本指でピンチイン・アウトを確認
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でマルチタッチズーム
パッケージ有効化手順
- Edit → Project Settings → Player で Active Input Handling = Both を選択
- Window → Package Manager から Input System を導入
- スクリプト先頭で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を実現しましょう。