213 lines
8.2 KiB
C#
213 lines
8.2 KiB
C#
using System;
|
|
using Core;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.InputSystem.EnhancedTouch;
|
|
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
|
|
|
namespace Minigames.StatueDressup.UI
|
|
{
|
|
/// <summary>
|
|
/// Detects and processes pinch gestures for scaling and rotation using Unity's new Input System (EnhancedTouch).
|
|
/// Also detects single-tap dismissal and provides keyboard shortcuts for editor testing.
|
|
/// </summary>
|
|
public class PinchGestureHandler : MonoBehaviour
|
|
{
|
|
[Header("Gesture Settings")]
|
|
[Tooltip("Minimum distance change to register as pinch scale gesture")]
|
|
[SerializeField] private float minPinchDistance = 10f;
|
|
|
|
[Tooltip("Sensitivity multiplier for scale changes")]
|
|
[SerializeField] private float scaleSensitivity = 0.01f;
|
|
|
|
[Tooltip("Sensitivity multiplier for rotation changes")]
|
|
[SerializeField] private float rotationSensitivity = 1.0f;
|
|
|
|
[Header("Editor Testing (Keyboard)")]
|
|
[Tooltip("Keyboard rotation speed in degrees per second")]
|
|
[SerializeField] private float keyboardRotationSpeed = 90f;
|
|
|
|
[Tooltip("Keyboard scale speed per second")]
|
|
[SerializeField] private float keyboardScaleSpeed = 0.5f;
|
|
|
|
// Events
|
|
public event Action<float> OnPinchScale;
|
|
public event Action<float> OnPinchRotate;
|
|
public event Action OnDismissTap;
|
|
|
|
private bool _isActive;
|
|
private float _previousDistance;
|
|
private float _previousAngle;
|
|
private double _touchStartTime;
|
|
private bool _wasTouchTracked;
|
|
|
|
/// <summary>
|
|
/// Activate gesture detection
|
|
/// </summary>
|
|
public void Activate()
|
|
{
|
|
_isActive = true;
|
|
_previousDistance = 0f;
|
|
_previousAngle = 0f;
|
|
_wasTouchTracked = false;
|
|
|
|
// Enable enhanced touch support for new Input System
|
|
if (!EnhancedTouchSupport.enabled)
|
|
{
|
|
EnhancedTouchSupport.Enable();
|
|
}
|
|
|
|
Logging.Debug("[PinchGestureHandler] Activated");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactivate gesture detection
|
|
/// </summary>
|
|
public void Deactivate()
|
|
{
|
|
_isActive = false;
|
|
Logging.Debug("[PinchGestureHandler] Deactivated");
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!_isActive) return;
|
|
|
|
// Handle touch input (mobile) - using new Input System
|
|
if (Touch.activeTouches.Count > 0)
|
|
{
|
|
HandleTouchInput();
|
|
}
|
|
// Handle keyboard input (editor testing)
|
|
else if (Application.isEditor)
|
|
{
|
|
HandleKeyboardInput();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Process touch input for pinch gestures and single-tap dismissal
|
|
/// </summary>
|
|
private void HandleTouchInput()
|
|
{
|
|
var activeTouches = Touch.activeTouches;
|
|
|
|
// Single tap for dismissal
|
|
if (activeTouches.Count == 1)
|
|
{
|
|
Touch touch = activeTouches[0];
|
|
|
|
// Track touch start time
|
|
if (touch.phase == UnityEngine.InputSystem.TouchPhase.Began)
|
|
{
|
|
_touchStartTime = touch.startTime;
|
|
_wasTouchTracked = true;
|
|
}
|
|
// Detect tap (touch began and ended quickly - within 0.3 seconds)
|
|
else if (touch.phase == UnityEngine.InputSystem.TouchPhase.Ended && _wasTouchTracked)
|
|
{
|
|
double touchDuration = Time.timeAsDouble - _touchStartTime;
|
|
if (touchDuration < 0.3)
|
|
{
|
|
Logging.Debug("[PinchGestureHandler] Single tap detected for dismissal");
|
|
OnDismissTap?.Invoke();
|
|
}
|
|
_wasTouchTracked = false;
|
|
}
|
|
}
|
|
// Two-finger pinch for scale and rotation
|
|
else if (activeTouches.Count == 2)
|
|
{
|
|
Touch touch0 = activeTouches[0];
|
|
Touch touch1 = activeTouches[1];
|
|
|
|
// Calculate current positions and distance
|
|
Vector2 currentTouch0 = touch0.screenPosition;
|
|
Vector2 currentTouch1 = touch1.screenPosition;
|
|
float currentDistance = Vector2.Distance(currentTouch0, currentTouch1);
|
|
float currentAngle = Mathf.Atan2(currentTouch1.y - currentTouch0.y, currentTouch1.x - currentTouch0.x) * Mathf.Rad2Deg;
|
|
|
|
// Initialize on first frame of pinch
|
|
if (touch0.phase == UnityEngine.InputSystem.TouchPhase.Began || touch1.phase == UnityEngine.InputSystem.TouchPhase.Began)
|
|
{
|
|
_previousDistance = currentDistance;
|
|
_previousAngle = currentAngle;
|
|
Logging.Debug("[PinchGestureHandler] Pinch gesture started");
|
|
return;
|
|
}
|
|
|
|
// Process pinch scale (distance change)
|
|
if (touch0.phase == UnityEngine.InputSystem.TouchPhase.Moved || touch1.phase == UnityEngine.InputSystem.TouchPhase.Moved)
|
|
{
|
|
if (_previousDistance > minPinchDistance)
|
|
{
|
|
float distanceDelta = currentDistance - _previousDistance;
|
|
float scaleDelta = distanceDelta * scaleSensitivity;
|
|
|
|
if (Mathf.Abs(scaleDelta) > 0.001f)
|
|
{
|
|
OnPinchScale?.Invoke(scaleDelta);
|
|
Logging.Debug($"[PinchGestureHandler] Scale delta: {scaleDelta:F3}");
|
|
}
|
|
}
|
|
|
|
// Process pinch rotation (angle change)
|
|
float angleDelta = Mathf.DeltaAngle(_previousAngle, currentAngle) * rotationSensitivity;
|
|
|
|
if (Mathf.Abs(angleDelta) > 0.5f)
|
|
{
|
|
OnPinchRotate?.Invoke(angleDelta);
|
|
Logging.Debug($"[PinchGestureHandler] Rotation delta: {angleDelta:F1}°");
|
|
}
|
|
|
|
// Update previous values
|
|
_previousDistance = currentDistance;
|
|
_previousAngle = currentAngle;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Process keyboard input for editor testing
|
|
/// Q/E for rotation, +/- for scale, Escape for dismissal
|
|
/// </summary>
|
|
private void HandleKeyboardInput()
|
|
{
|
|
var keyboard = Keyboard.current;
|
|
if (keyboard == null) return;
|
|
|
|
// Rotation with Q/E
|
|
if (keyboard.qKey.isPressed)
|
|
{
|
|
float rotateDelta = -keyboardRotationSpeed * Time.deltaTime;
|
|
OnPinchRotate?.Invoke(rotateDelta);
|
|
}
|
|
else if (keyboard.eKey.isPressed)
|
|
{
|
|
float rotateDelta = keyboardRotationSpeed * Time.deltaTime;
|
|
OnPinchRotate?.Invoke(rotateDelta);
|
|
}
|
|
|
|
// Scale with +/- (equals key is where + is on keyboard)
|
|
if (keyboard.equalsKey.isPressed || keyboard.numpadPlusKey.isPressed)
|
|
{
|
|
float scaleDelta = keyboardScaleSpeed * Time.deltaTime;
|
|
OnPinchScale?.Invoke(scaleDelta);
|
|
}
|
|
else if (keyboard.minusKey.isPressed || keyboard.numpadMinusKey.isPressed)
|
|
{
|
|
float scaleDelta = -keyboardScaleSpeed * Time.deltaTime;
|
|
OnPinchScale?.Invoke(scaleDelta);
|
|
}
|
|
|
|
// Dismissal with Escape or Space
|
|
if (keyboard.escapeKey.wasPressedThisFrame || keyboard.spaceKey.wasPressedThisFrame)
|
|
{
|
|
Logging.Debug("[PinchGestureHandler] Keyboard dismissal detected");
|
|
OnDismissTap?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|