using UnityEngine; using UnityEngine.InputSystem; using System; public class InputManager : MonoBehaviour { private static InputManager _instance; public static InputManager Instance { get { if (_instance == null) { _instance = FindAnyObjectByType(); if (_instance == null) { var go = new GameObject("InputManager"); _instance = go.AddComponent(); DontDestroyOnLoad(go); } } return _instance; } } private PlayerInput playerInput; private InputAction touchPressAction; private InputAction touchPositionAction; private ITouchInputConsumer defaultConsumer; private bool isTouchHeld = false; private bool lastFrameInteracted = false; // Tap/drag detection state private Vector2 pressStartPosition; private float pressStartTime; private bool isPressed = false; private bool isDragging = false; private float dragThreshold = 10f; // pixels private float tapTimeThreshold = 0.2f; // seconds void Awake() { _instance = this; DontDestroyOnLoad(gameObject); playerInput = GetComponent(); if (playerInput == null) { Debug.LogError("[InputManager] InputManager requires a PlayerInput component attached to the same GameObject."); return; } // Find actions by name in the assigned action map touchPressAction = playerInput.actions.FindAction("TouchPress", false); touchPositionAction = playerInput.actions.FindAction("TouchPosition", false); } void OnEnable() { if (touchPressAction != null) { touchPressAction.started += OnTouchPressStarted; touchPressAction.canceled += OnTouchPressCanceled; } if (touchPositionAction != null) touchPositionAction.performed += OnTouchPositionPerformed; } void OnDisable() { if (touchPressAction != null) { touchPressAction.started -= OnTouchPressStarted; touchPressAction.canceled -= OnTouchPressCanceled; } if (touchPositionAction != null) touchPositionAction.performed -= OnTouchPositionPerformed; } public void SetDefaultConsumer(ITouchInputConsumer consumer) { defaultConsumer = consumer; } private void OnTouchPressStarted(InputAction.CallbackContext ctx) { // Touch started (finger down) Vector2 screenPos = touchPositionAction.ReadValue(); Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos); Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y); lastFrameInteracted = TryDelegateToInteractable(worldPos2D); if (!lastFrameInteracted) { pressStartPosition = screenPos; pressStartTime = Time.time; isPressed = true; isDragging = false; defaultConsumer?.OnHoldStart(worldPos2D); } } private void OnTouchPressCanceled(InputAction.CallbackContext ctx) { Vector2 screenPos = touchPositionAction.ReadValue(); Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos); Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y); if (!lastFrameInteracted) { float timeHeld = Time.time - pressStartTime; float dist = Vector2.Distance(screenPos, pressStartPosition); if (!isDragging && timeHeld < tapTimeThreshold && dist < dragThreshold) { defaultConsumer?.OnTap(worldPos2D); } defaultConsumer?.OnHoldEnd(worldPos2D); } isPressed = false; isDragging = false; lastFrameInteracted = false; } private void OnTouchPositionPerformed(InputAction.CallbackContext ctx) { // No longer needed, OnTouchHeld will be handled in Update } void Update() { if (isPressed && touchPositionAction != null) { Vector2 screenPos = touchPositionAction.ReadValue(); Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos); Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y); defaultConsumer?.OnHold(worldPos2D); } } private bool TryDelegateToInteractable(Vector2 worldPos) { // Raycast at the world position to find an Interactable Collider2D hit = Physics2D.OverlapPoint(worldPos); if (hit != null) { var interactable = hit.GetComponent(); if (interactable != null) { interactable.OnTap(worldPos); return true; } } return false; } }