カメラ移動スクリプト

1.直接的な位置の更新:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

[RequireComponent(typeof(Camera))]
public class SceneViewCamera_1 : MonoBehaviour
{
	[SerializeField] private float pinchSpeed;
	[SerializeField] private float dragThreshold;

	private Vector2 touchStartPos;
	private float initialFingersDistance;
	private Vector3 initialCameraPosition;
	private bool isPinching = false;
	private int? activeTouchId = null;
	private bool canMoveCamera = false;

	private Camera mainCamera;
	private Transform cameraTransform;

	private RaycastHit[] raycastHitCache = new RaycastHit[1];
	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();

	private void Start()
	{
		mainCamera = Camera.main;
		cameraTransform = transform;
	}

	private void Update()
	{
		TouchUpdate();
	}

	private void TouchUpdate()
	{
		if (Input.touchCount == 1)
		{
			HandleSingleTouch(Input.GetTouch(0));
		}
		else if (Input.touchCount == 2)
		{
			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
		}
		else
		{
			ResetTouchState();
		}
	}

	private void HandleSingleTouch(Touch touch)
	{
		switch (touch.phase)
		{
			case TouchPhase.Began:
				if (!activeTouchId.HasValue)
				{
					activeTouchId = touch.fingerId;
					touchStartPos = touch.position;
					touchPositions[touch.fingerId] = touch.position;
					canMoveCamera = CheckIfCanMoveCamera(touch.position);
					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
				}
				break;

			case TouchPhase.Moved:
				if (activeTouchId == touch.fingerId && canMoveCamera)
				{
					float dragDistance = Vector2.Distance(touchStartPos, touch.position);
					Debug.Log($"Drag distance: {dragDistance}");
					if (dragDistance > dragThreshold)
					{
						TouchDrag(touch.position);
						Debug.Log("Camera moved");
					}
				}
				break;

			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				if (activeTouchId == touch.fingerId)
				{
					ResetTouchState();
				}
				break;
		}
	}

	private void HandlePinch(Touch touch1, Touch touch2)
	{
		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
		{
			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			initialCameraPosition = cameraTransform.position;
			isPinching = true;
		}
		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
		{
			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			float scaleFactor = initialFingersDistance / currentFingersDistance;
			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
			cameraTransform.position = newPosition;
		}
		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
		{
			isPinching = false;
		}
	}

	private bool CheckIfCanMoveCamera(Vector2 touchPos)
	{
		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;

		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
		{
			return touchedObject.CompareTag("Ground");
		}
		return false;
	}

	private void TouchDrag(Vector2 touchPos)
	{
		if (!canMoveCamera) return;

		Vector2 diff = touchPos - touchStartPos;
		Vector3 worldSpaceDiff = mainCamera.ScreenToViewportPoint(new Vector3(diff.x, diff.y, 0)) - mainCamera.ScreenToViewportPoint(Vector3.zero);
		worldSpaceDiff.z = 0; // z軸の移動を無視

		// カメラの右方向と上方向のベクトルを取得
		Vector3 cameraRight = cameraTransform.right;
		Vector3 cameraUp = cameraTransform.up;

		// 移動量を計算(x軸とy軸を反転)
		Vector3 movement = (-worldSpaceDiff.x * cameraRight + -worldSpaceDiff.y * cameraUp) * 10f;

		Debug.Log($"Screen diff: {diff}, World space diff: {worldSpaceDiff}, Movement: {movement}");

		// カメラの位置を更新
		Vector3 newPosition = cameraTransform.position + movement;
		cameraTransform.position = newPosition;

		touchStartPos = touchPos;
	}

	private void ResetTouchState()
	{
		activeTouchId = null;
		isPinching = false;
		touchPositions.Clear();
		canMoveCamera = false;
	}
}

利点:
指の動きに正確に追従するため、ユーザーの意図通りの動きを実現できます。
フレームレートに依存せず、一貫した動きを提供します。
実装が比較的シンプルで理解しやすいです。
欠点:
急激な動きをすると、カメラの動きが不自然に感じる可能性があります。
高速な動きに対して、カメラが追いつけない場合があります。
スクリーン座標からワールド座標への変換が必要で、計算コストがやや高くなります。

2デルタ移動の使用:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

[RequireComponent(typeof(Camera))]
public class SceneViewCamera_2 : MonoBehaviour
{
	[SerializeField] private float pinchSpeed;
	[SerializeField] private float dragThreshold;
	[SerializeField] private float dragSpeed = 3f; // 新しく追加:ドラッグ速度調整用

	private Vector2 touchStartPos;
	private float initialFingersDistance;
	private Vector3 initialCameraPosition;
	private bool isPinching = false;
	private int? activeTouchId = null;
	private bool canMoveCamera = false;

	private Camera mainCamera;
	private Transform cameraTransform;

	private RaycastHit[] raycastHitCache = new RaycastHit[1];
	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();

	private void Start()
	{
		mainCamera = Camera.main;
		cameraTransform = transform;
	}

	private void Update()
	{
		TouchUpdate();
	}

	private void TouchUpdate()
	{
		if (Input.touchCount == 1)
		{
			HandleSingleTouch(Input.GetTouch(0));
		}
		else if (Input.touchCount == 2)
		{
			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
		}
		else
		{
			ResetTouchState();
		}
	}

	private void HandleSingleTouch(Touch touch)
	{
		switch (touch.phase)
		{
			case TouchPhase.Began:
				if (!activeTouchId.HasValue)
				{
					activeTouchId = touch.fingerId;
					touchStartPos = touch.position;
					touchPositions[touch.fingerId] = touch.position;
					canMoveCamera = CheckIfCanMoveCamera(touch.position);
					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
				}
				break;

			case TouchPhase.Moved:
				if (activeTouchId == touch.fingerId && canMoveCamera)
				{
					TouchDrag(touch);
					Debug.Log("Camera moved");
				}
				break;

			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				if (activeTouchId == touch.fingerId)
				{
					ResetTouchState();
				}
				break;
		}
	}

	private void HandlePinch(Touch touch1, Touch touch2)
	{
		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
		{
			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			initialCameraPosition = cameraTransform.position;
			isPinching = true;
		}
		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
		{
			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			float scaleFactor = initialFingersDistance / currentFingersDistance;
			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
			cameraTransform.position = newPosition;
		}
		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
		{
			isPinching = false;
		}
	}

	private bool CheckIfCanMoveCamera(Vector2 touchPos)
	{
		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;

		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
		{
			return touchedObject.CompareTag("Ground");
		}
		return false;
	}

	private void TouchDrag(Touch touch)
	{
		if (!canMoveCamera) return;

		Vector2 deltaPosition = touch.deltaPosition;
		Vector3 worldSpaceDelta = mainCamera.ScreenToViewportPoint(new Vector3(deltaPosition.x, deltaPosition.y, 0)) - mainCamera.ScreenToViewportPoint(Vector3.zero);
		worldSpaceDelta.z = 0; // z軸の移動を無視

		// カメラの右方向と上方向のベクトルを取得
		Vector3 cameraRight = cameraTransform.right;
		Vector3 cameraUp = cameraTransform.up;

		// 移動量を計算(x軸とy軸を反転)
		Vector3 movement = (-worldSpaceDelta.x * cameraRight + -worldSpaceDelta.y * cameraUp) * dragSpeed;

		Debug.Log($"Delta position: {deltaPosition}, World space delta: {worldSpaceDelta}, Movement: {movement}");

		// カメラの位置を更新
		cameraTransform.position += movement;
	}

	private void ResetTouchState()
	{
		activeTouchId = null;
		isPinching = false;
		touchPositions.Clear();
		canMoveCamera = false;
	}
}

Touch.deltaPositionを使用して、フレーム間の指の動きを直接反映させます。
利点:
フレーム間の細かい動きを捉えられるため、滑らかな動きを実現できます。
Touch.deltaPositionを直接使用するため、計算が比較的シンプルです。
連続的な動きに対して効果的です。
欠点:
フレームレートに依存するため、デバイスによって動きが異なる可能性があります。
急激な動きに対しては精度が落ちる可能性があります。
累積誤差が生じる可能性があり、長時間の操作で精度が低下することがあります。

3ビューポートスペースでの移動:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

[RequireComponent(typeof(Camera))]
public class SceneViewCamera_3 : MonoBehaviour
{
	[SerializeField] private float pinchSpeed = 0.1f;
	[SerializeField] private float dragThreshold = 5f;
	[SerializeField] private float dragSpeed = 1f;

	private Vector2 touchStartPos;
	private float initialFingersDistance;
	private Vector3 initialCameraPosition;
	private bool isPinching = false;
	private int? activeTouchId = null;
	private bool canMoveCamera = false;

	private Camera mainCamera;
	private Transform cameraTransform;

	private RaycastHit[] raycastHitCache = new RaycastHit[1];
	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();

	private void Start()
	{
		mainCamera = Camera.main;
		cameraTransform = transform;
	}

	private void Update()
	{
		TouchUpdate();
	}

	private void TouchUpdate()
	{
		if (Input.touchCount == 1)
		{
			HandleSingleTouch(Input.GetTouch(0));
		}
		else if (Input.touchCount == 2)
		{
			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
		}
		else
		{
			ResetTouchState();
		}
	}

	private void HandleSingleTouch(Touch touch)
	{
		switch (touch.phase)
		{
			case TouchPhase.Began:
				if (!activeTouchId.HasValue)
				{
					activeTouchId = touch.fingerId;
					touchStartPos = touch.position;
					touchPositions[touch.fingerId] = touch.position;
					canMoveCamera = CheckIfCanMoveCamera(touch.position);
					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
				}
				break;

			case TouchPhase.Moved:
				if (activeTouchId == touch.fingerId && canMoveCamera)
				{
					TouchDrag(touch);
					Debug.Log("Camera moved");
				}
				break;

			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				if (activeTouchId == touch.fingerId)
				{
					ResetTouchState();
				}
				break;
		}
	}

	private void HandlePinch(Touch touch1, Touch touch2)
	{
		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
		{
			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			initialCameraPosition = cameraTransform.position;
			isPinching = true;
		}
		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
		{
			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			float scaleFactor = initialFingersDistance / currentFingersDistance;
			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
			cameraTransform.position = newPosition;
		}
		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
		{
			isPinching = false;
		}
	}

	private bool CheckIfCanMoveCamera(Vector2 touchPos)
	{
		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;

		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
		{
			return touchedObject.CompareTag("Ground");
		}
		return false;
	}

	private void TouchDrag(Touch touch)
	{
		if (!canMoveCamera) return;

		Vector2 viewportDelta = mainCamera.ScreenToViewportPoint(touch.position) - mainCamera.ScreenToViewportPoint(touchStartPos);

		// カメラの右方向と上方向のベクトルを取得
		Vector3 cameraRight = cameraTransform.right;
		Vector3 cameraUp = cameraTransform.up;

		// 移動量を計算(x軸とy軸を反転し、y軸の符号を変更)
		Vector3 move = (-viewportDelta.x * cameraRight - viewportDelta.y * cameraUp) * dragSpeed;

		// カメラの位置を更新
		cameraTransform.position += move;

		Debug.Log($"Viewport delta: {viewportDelta}, Movement: {move}");

		touchStartPos = touch.position;
	}

	private void ResetTouchState()
	{
		activeTouchId = null;
		isPinching = false;
		touchPositions.Clear();
		canMoveCamera = false;
	}
}

ビューポート座標を使用して、画面サイズに依存しない移動を実現します。
利点:
画面サイズに依存しない一貫した動きを提供します。
異なる解像度のデバイスでも同じ感覚で操作できます。
スケーリングが容易で、カメラの動きの調整が簡単です。
欠点:
ワールド座標系との変換が必要で、やや複雑になる可能性があります。
3D空間での深度の違いによる見かけの移動速度の差を考慮する必要があります。
特定のシーン構造に依存する場合、調整が必要になることがあります。

4補間を使用したスムーズな移動:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

[RequireComponent(typeof(Camera))]
public class SceneViewCamera_4 : MonoBehaviour
{
	[SerializeField] private float pinchSpeed = 0.1f;
	[SerializeField] private float dragThreshold = 5f;
	[SerializeField] private float dragSpeed = 5f;
	[SerializeField] private float smoothTime = 0.2f; // スムージング時間

	private Vector2 touchStartPos;
	private float initialFingersDistance;
	private Vector3 initialCameraPosition;
	private bool isPinching = false;
	private int? activeTouchId = null;
	private bool canMoveCamera = false;

	private Camera mainCamera;
	private Transform cameraTransform;

	private RaycastHit[] raycastHitCache = new RaycastHit[1];
	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();

	private Vector3 targetPosition;
	private Vector3 velocity = Vector3.zero;

	private void Start()
	{
		mainCamera = Camera.main;
		cameraTransform = transform;
		targetPosition = cameraTransform.position;
	}

	private void Update()
	{
		TouchUpdate();
		SmoothCameraMovement();
	}

	private void TouchUpdate()
	{
		if (Input.touchCount == 1)
		{
			HandleSingleTouch(Input.GetTouch(0));
		}
		else if (Input.touchCount == 2)
		{
			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
		}
		else
		{
			ResetTouchState();
		}
	}

	private void HandleSingleTouch(Touch touch)
	{
		switch (touch.phase)
		{
			case TouchPhase.Began:
				if (!activeTouchId.HasValue)
				{
					activeTouchId = touch.fingerId;
					touchStartPos = touch.position;
					touchPositions[touch.fingerId] = touch.position;
					canMoveCamera = CheckIfCanMoveCamera(touch.position);
					Debug.Log($"Touch began: canMoveCamera = {canMoveCamera}");
				}
				break;

			case TouchPhase.Moved:
				if (activeTouchId == touch.fingerId && canMoveCamera)
				{
					TouchDrag(touch);
					Debug.Log("Camera moved");
				}
				break;

			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				if (activeTouchId == touch.fingerId)
				{
					ResetTouchState();
				}
				break;
		}
	}

	private void HandlePinch(Touch touch1, Touch touch2)
	{
		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
		{
			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			initialCameraPosition = cameraTransform.position;
			isPinching = true;
		}
		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
		{
			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			float scaleFactor = initialFingersDistance / currentFingersDistance;
			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
			targetPosition = newPosition;
		}
		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
		{
			isPinching = false;
		}
	}

	private bool CheckIfCanMoveCamera(Vector2 touchPos)
	{
		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;

		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
		{
			return touchedObject.CompareTag("Ground");
		}
		return false;
	}

	private void TouchDrag(Touch touch)
	{
		if (!canMoveCamera) return;

		Vector2 viewportDelta = mainCamera.ScreenToViewportPoint(touch.position) - mainCamera.ScreenToViewportPoint(touchStartPos);

		// カメラの右方向と上方向のベクトルを取得
		Vector3 cameraRight = cameraTransform.right;
		Vector3 cameraUp = cameraTransform.up;

		// 移動量を計算(x軸とy軸を反転)
		Vector3 move = (-viewportDelta.x * cameraRight - viewportDelta.y * cameraUp) * dragSpeed;

		targetPosition = cameraTransform.position + move;

		Debug.Log($"Viewport delta: {viewportDelta}, Target movement: {move}");

		touchStartPos = touch.position;
	}

	private void SmoothCameraMovement()
	{
		cameraTransform.position = Vector3.SmoothDamp(cameraTransform.position, targetPosition, ref velocity, smoothTime);
	}

	private void ResetTouchState()
	{
		activeTouchId = null;
		isPinching = false;
		touchPositions.Clear();
		canMoveCamera = false;
	}
}

直接的な移動が急すぎる場合、補間を使用してスムーズな動きを実現できます。
利点:
なめらかで自然な動きを実現できます。
急激な入力に対してもスムーズな反応を示します。
ユーザー体験を向上させ、より洗練された印象を与えます。
欠点:
実際の指の位置とカメラの位置にわずかな遅延が生じます。
補間パラメータの調整が必要で、適切な値を見つけるのに時間がかかる場合があります。
計算量がやや増加し、パフォーマンスに影響を与える可能性があります。

5シンプル移動:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

[RequireComponent(typeof(Camera))]
public class SceneViewCamera_0 : MonoBehaviour
{
	[SerializeField] private float moveSpeed = 0.8f;
	[SerializeField] private float pinchSpeed;
	[SerializeField] private float dragThreshold;

	private Vector2 touchStartPos;
	private float initialFingersDistance;
	private Vector3 initialCameraPosition;
	private bool isPinching = false;
	private int? activeTouchId = null;
	private bool canMoveCamera = false;

	private Camera mainCamera;
	private Transform cameraTransform;

	private RaycastHit[] raycastHitCache = new RaycastHit[1];
	private Dictionary<int, Vector2> touchPositions = new Dictionary<int, Vector2>();

	private void Start()
	{
		mainCamera = Camera.main;
		cameraTransform = transform;
	}

	private void Update()
	{
		TouchUpdate();
	}

	private void TouchUpdate()
	{
		if (Input.touchCount == 1)
		{
			HandleSingleTouch(Input.GetTouch(0));
		}
		else if (Input.touchCount == 2)
		{
			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
		}
		else
		{
			ResetTouchState();
		}
	}

	private void HandleSingleTouch(Touch touch)
	{
		switch (touch.phase)
		{
			case TouchPhase.Began:
				if (!activeTouchId.HasValue)
				{
					activeTouchId = touch.fingerId;
					touchStartPos = touch.position;
					touchPositions[touch.fingerId] = touch.position;
					canMoveCamera = CheckIfCanMoveCamera(touch.position);
					//Debug.Log($"Touch began: {activeTouchId}, Position: {touch.position}");
				}
				break;

			case TouchPhase.Moved:
				if (activeTouchId == touch.fingerId && canMoveCamera)
				{
					float dragDistance = Vector2.Distance(touchStartPos, touch.position);
					if (dragDistance > dragThreshold)
					{
						TouchDrag(touch.position);
					}
					//Debug.Log($"Touch moved: {activeTouchId}, Position: {touch.position}, Distance: {dragDistance}");
				}
				break;

			case TouchPhase.Stationary:
				//Debug.Log($"Touch stationary: {activeTouchId}, Position: {touch.position}");
				break;

			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				if (activeTouchId == touch.fingerId)
				{
					//Debug.Log($"Touch ended/canceled: {activeTouchId}");
					ResetTouchState();
				}
				break;
		}
	}

	private void HandlePinch(Touch touch1, Touch touch2)
	{
		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
		{
			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			initialCameraPosition = cameraTransform.position;
			isPinching = true;
		}
		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
		{
			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			float scaleFactor = initialFingersDistance / currentFingersDistance;
			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
			cameraTransform.position = newPosition;
		}
		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
		{
			isPinching = false;
		}
	}
	private bool CheckIfCanMoveCamera(Vector2 touchPos)
	{
		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;

		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider")))
		{
			return touchedObject.CompareTag("Ground");
		}
		return false;
	}

	private void TouchDrag(Vector2 touchPos)
	{
		if (!canMoveCamera) return;

		Vector2 diff = touchPos - touchStartPos;
		if (diff.sqrMagnitude >= Vector2.kEpsilonNormalSqrt)
		{
			cameraTransform.Translate(-diff * Time.deltaTime * moveSpeed);
			touchStartPos = touchPos;
		}
	}

	private void ResetTouchState()
	{
		activeTouchId = null;
		isPinching = false;
		touchPositions.Clear();
		canMoveCamera = false;
		//Debug.Log("Touch state reset");
	}
}

6結局採用したやつ:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using TMPro;

[RequireComponent(typeof(Camera))]
public class ImprovedSceneViewCamera : MonoBehaviour
{
	[SerializeField] private float pinchSpeed = 20f;

	private Vector2 touchStartPos;
	private Vector3 touchWorldStartPos;
	private float initialFingersDistance;
	private Vector3 initialCameraPosition;
	private bool isPinching = false;
	private int? activeTouchId = null;
	private bool canMoveCamera = false;

	private Camera mainCamera;
	private Transform cameraTransform;

	private void Start()
	{
		mainCamera = Camera.main;
		cameraTransform = transform;
	}

	private void Update()
	{
		TouchUpdate();
	}

	private void TouchUpdate()
	{
		if (Input.touchCount == 1)
		{
			HandleSingleTouch(Input.GetTouch(0));
		}
		else if (Input.touchCount == 2)
		{
			HandlePinch(Input.GetTouch(0), Input.GetTouch(1));
		}
		else
		{
			ResetTouchState();
		}
	}

	private void HandleSingleTouch(Touch touch)
	{
		switch (touch.phase)
		{
			case TouchPhase.Began:
				if (!activeTouchId.HasValue)
				{
					activeTouchId = touch.fingerId;
					touchStartPos = touch.position;
					touchWorldStartPos = GetWorldPosition(touchStartPos);
					canMoveCamera = CheckIfCanMoveCamera(touch.position);
				}
				break;

			case TouchPhase.Moved:
				if (activeTouchId == touch.fingerId)
				{
					if (canMoveCamera)
					{
						TouchDrag(touch);
					}
					else
					{
						// ここで他のタッチ処理を行う(必要に応じて)
					}
				}
				break;

			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				if (activeTouchId == touch.fingerId)
				{
					ResetTouchState();
				}
				break;
		}
	}

	private void HandlePinch(Touch touch1, Touch touch2)
	{
		if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
		{
			initialFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			initialCameraPosition = cameraTransform.position;
			isPinching = true;
		}
		else if ((touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) && isPinching)
		{
			float currentFingersDistance = Vector2.Distance(touch1.position, touch2.position);
			float scaleFactor = initialFingersDistance / currentFingersDistance;
			Vector3 newPosition = initialCameraPosition + (cameraTransform.forward * (1f - scaleFactor) * pinchSpeed);
			cameraTransform.position = newPosition;
		}
		else if ((touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended) && isPinching)
		{
			isPinching = false;
		}
	}

	private bool CheckIfCanMoveCamera(Vector2 touchPos)
	{
		if (EventSystem.current.IsPointerOverGameObject(activeTouchId.Value)) return false;

		if (TouchUtility.TryGetTouchedObject(out GameObject touchedObject, layerMask: LayerMask.GetMask("Ground", "EggCollider", "GetWorks")))
		{
			return touchedObject.CompareTag("Ground");
		}

		return false;
	}

	private void TouchDrag(Touch touch)
	{
		if (!canMoveCamera) return;

		Vector3 currentTouchWorldPos = GetWorldPosition(touch.position);
		Vector3 worldSpaceDelta = touchWorldStartPos - currentTouchWorldPos;

		// カメラの位置を更新
		cameraTransform.position += worldSpaceDelta;
	}

	private Vector3 GetWorldPosition(Vector2 screenPosition)
	{
		Ray ray = mainCamera.ScreenPointToRay(screenPosition);
		Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
		if (groundPlane.Raycast(ray, out float distance))
		{
			return ray.GetPoint(distance);
		}
		return Vector3.zero;
	}

	private void ResetTouchState()
	{
		activeTouchId = null;
		isPinching = false;
		canMoveCamera = false;
	}
}

AIにiPhoneの写真アプリみたいにって言ったら、これ出してきた。

というか、エディタ上でUnity Remoteで動かすときと、Buildして実機で動かすときとじゃ、全然挙動が違う。それ知ってればサクッとできたのに。というお話。

マルチ集団(Multi-Group)

小さな抵抗 大きな勘違い

おすすめ記事

コメントを残す

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