[Unity]:ドラッグ&ピンチイン・ピンチアウトの入力コントロール

先日リリースした「まちがい探し3D」では、少し特殊な入力インターフェースを利用しています。

Moku

Moku
まちがい探し3D
★★★★☆
28件の評価
App Store

  • ドラッグで視点の移動
  • ピンチイン・ピンチアウトで視点の縮小・拡大
  • タップでオブジェクトの選択

これらの入力をコントロールするためのスクリプトを公開します。

using UnityEngine;
using System.Collections;

public class CameraController : MonoBehaviour {
	const float ROTATION_SPEED =  5.0f;
	const float ZOOM_SPEED = 200.0f;
	
	private Vector3 original;
	private float angle_x = 0.0f;
	private float angle_y = 0.0f;
	
	private bool isDragging = false;
	private bool isDragged = false;
	private bool isPinched = false;
	private float interval = 0.0f;

	// Use this for initialization
	void Start () {
		Vector3 angles = transform.eulerAngles;
		angle_x = angles.y;
		angle_y = angles.x;
		original = transform.position;
	}
	
	void OnGUI() {
		if (Input.touchCount == 1 && !isPinched) {
			if (Event.current.type == EventType.MouseDrag) {
				isDragging = true;
				isDragged = true;
			} else {
				isDragging = false;
				if (Event.current.type == EventType.MouseUp) {
					if (!isDragged) Tap(Input.mousePosition);
					else isDragged = false;
				}
			}
		} else if (Input.touchCount == 0) {
			isPinched = false;
		}
	}
	
	void Update () {
		if (Input.touchCount == 2) {
			if (Input.touches[0].phase == TouchPhase.Began || Input.touches[1].phase == TouchPhase.Began) {
				interval = Vector2.Distance(Input.touches[0].position, Input.touches[1].position);
			}
			float tmpInterval = Vector2.Distance(Input.touches[0].position, Input.touches[1].position);
			original.z += (tmpInterval - interval) / ZOOM_SPEED;
			if (original.z > 0) original.z = 0;
			interval = tmpInterval;

			transform.position = transform.rotation * original;
			isPinched = true;
		} else if (isDragging) {
			angle_x += Input.GetAxis("Mouse X") * ROTATION_SPEED;
	        angle_y -= Input.GetAxis("Mouse Y") * ROTATION_SPEED;
	        
	        transform.rotation = Quaternion.Euler(angle_y, angle_x, 0);
	        transform.position = transform.rotation * original;
		}
	}
	
	private void Tap(Vector3 point) {
		// タップ時の処理を記述
	}
}

若干、難解なコードになってしまっていますが、元々ドラッグのみを実現するスクリプトにタップとピンチイン・ピンチアウトを無理くり付け足したため、このような状態になってしまいました。
OnGUI()を使わずにUpdate()でまとめて書き直した方がスッキリするでしょう。

画面にタッチされた時に触れた点が2カ所ならピンチイン・アウトの開始として、その2点間の距離をintervalに保持しておくと同時にisPinchedフラグを立てておきます。
このisPinchedフラグは、指が離れる時に指1本だけが残り不正なドラッグ・タップが起こらないよう判定するためのもので、タッチが検出されなくなると寝かせるようにしています。
ピンチイン・アウト中は前回のintervalと比較計算しズームイン・アウトの処理を行います。

触れた点が1カ所の場合、Event.current.type == EventType.MouseDragによりドラッグ中であると判定されたらisDraggingとisDraggedフラグを立てます。
isDraggingフラグが立っている場合には回転の処理を行います。
originalに初期位置、angle_x, angle_yに初期位置での向きを保持しており、ドラッグによりangle_*を変更し、その角度に基づき位置を計算します。
原点を中心に回転し、常に原点の方を向く事になります。

指が離れた場合にはisDraggedフラグが寝ていればタップの処理を行います。
つまりタップに関しては指が離れた時点での処理ということになりますが、ドラッグも実現するために選択の余地はありませんでした。

[Unity]:ドラッグ&ピンチイン・ピンチアウトの入力コントロール」への4件のフィードバック

  1. mackie

    “ZOOM_SPEED”がUpdate()内で”ZOON_SPEED”になってますよ。

    返信
    1. moku 投稿作成者

      ご指摘ありがとうございます。
      修正いたしました。

      返信
  2. こんにちは。
    スクリプト使わせて頂きました。
    1つ気になった点がありまして、ピンチインやドラッグの操作を最初に行った時に
    カメラが初期位置とは違う位置にズレルのですが、これはどのアタリを触れは良いのでしょうか?

    返信
    1. moku 投稿作成者

      このアプリ用のスクリプトの場合、カメラがx = 0, z < 0で原点方向を向いている前提になっているので、カメラの初期位置がそれ以外の場合に不具合があるかも知れません。 カメラの初期状態を取得しているStart()の中、それと移動の計算をしているUpdate()の中身を全体的に見直す必要があるかもしれません。 だいぶ以前に書いたもので、今見直してみるとかなり煩雑なスクリプトなので、的確な回答ができなくてすいません。

      返信

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です