using UnityEngine; using UnityEngine.InputSystem; /// /// 게임패드 입력을 처리하여 드론 카메라 제어에 필요한 값을 제공합니다. /// Unity Input System의 Gamepad.current를 사용합니다. /// public class GamepadInputHandler : MonoBehaviour { [Header("Deadzone Settings")] [SerializeField] private float stickDeadzone = 0.15f; [Header("Response Curve")] [SerializeField] private float stickExponent = 2.0f; // 비선형 응답 곡선 (2 = 제곱) [Header("Speed Multipliers")] [SerializeField] private float slowMultiplier = 0.3f; // LT 누를 때 [SerializeField] private float boostMultiplier = 3.0f; // RT 누를 때 // 스틱 값 (데드존 + 커브 적용 후) public Vector2 LeftStick { get; private set; } public Vector2 RightStick { get; private set; } // 트리거 값 (0~1) public float LeftTrigger { get; private set; } public float RightTrigger { get; private set; } // 속도 배율 (LT/RT 기반) public float SpeedMultiplier { get; private set; } = 1f; // 버튼 상태 (이번 프레임에 눌렸는지) public bool ButtonSouthPressed { get; private set; } // A (Xbox) / Cross (PS) public bool ButtonEastPressed { get; private set; } // B (Xbox) / Circle (PS) public bool ButtonNorthPressed { get; private set; } // Y (Xbox) / Triangle (PS) public bool ButtonWestPressed { get; private set; } // X (Xbox) / Square (PS) public bool LeftShoulderPressed { get; private set; } // LB public bool RightShoulderPressed { get; private set; }// RB public bool LeftShoulderHeld { get; private set; } public bool RightShoulderHeld { get; private set; } public bool StartPressed { get; private set; } // D-pad는 소비형 플래그 (LateUpdate에서 읽은 뒤 자동 리셋) private bool _dpadUp, _dpadDown, _dpadLeft, _dpadRight; // D-pad 이전 프레임 상태 (엣지 감지용) private bool _dpadUpHeld, _dpadDownHeld, _dpadLeftHeld, _dpadRightHeld; public bool DpadUpPressed => _dpadUp; public bool DpadDownPressed => _dpadDown; public bool DpadLeftPressed => _dpadLeft; public bool DpadRightPressed => _dpadRight; // 게임패드 연결 상태 public bool IsGamepadConnected => Gamepad.current != null; private bool wasConnected = false; private void Update() { var gamepad = Gamepad.current; if (gamepad == null) { if (wasConnected) { Debug.Log("[GamepadInputHandler] 게임패드 연결 해제됨"); wasConnected = false; } ResetAll(); return; } if (!wasConnected) { Debug.Log($"[GamepadInputHandler] 게임패드 연결됨: {gamepad.displayName}"); wasConnected = true; } // 스틱 LeftStick = ApplyDeadzoneAndCurve(gamepad.leftStick.ReadValue()); RightStick = ApplyDeadzoneAndCurve(gamepad.rightStick.ReadValue()); // 트리거 LeftTrigger = gamepad.leftTrigger.ReadValue(); RightTrigger = gamepad.rightTrigger.ReadValue(); // 속도 배율 계산 SpeedMultiplier = CalculateSpeedMultiplier(); // 버튼 (이번 프레임 pressed) ButtonSouthPressed = gamepad.buttonSouth.wasPressedThisFrame; ButtonEastPressed = gamepad.buttonEast.wasPressedThisFrame; ButtonNorthPressed = gamepad.buttonNorth.wasPressedThisFrame; ButtonWestPressed = gamepad.buttonWest.wasPressedThisFrame; LeftShoulderPressed = gamepad.leftShoulder.wasPressedThisFrame; RightShoulderPressed = gamepad.rightShoulder.wasPressedThisFrame; LeftShoulderHeld = gamepad.leftShoulder.isPressed; RightShoulderHeld = gamepad.rightShoulder.isPressed; StartPressed = gamepad.startButton.wasPressedThisFrame; // D-pad: ReadValue()로 방향 판별 (일부 게임패드에서 wasPressedThisFrame이 안 먹는 경우 대응) Vector2 dpadValue = gamepad.dpad.ReadValue(); bool dpadUpNow = dpadValue.y > 0.5f; bool dpadDownNow = dpadValue.y < -0.5f; bool dpadLeftNow = dpadValue.x < -0.5f; bool dpadRightNow = dpadValue.x > 0.5f; // 엣지 감지: 이전 프레임에 안 눌려있다가 이번에 눌린 경우만 플래그 세움 if (dpadUpNow && !_dpadUpHeld) _dpadUp = true; if (dpadDownNow && !_dpadDownHeld) _dpadDown = true; if (dpadLeftNow && !_dpadLeftHeld) _dpadLeft = true; if (dpadRightNow && !_dpadRightHeld) _dpadRight = true; _dpadUpHeld = dpadUpNow; _dpadDownHeld = dpadDownNow; _dpadLeftHeld = dpadLeftNow; _dpadRightHeld = dpadRightNow; } private Vector2 ApplyDeadzoneAndCurve(Vector2 raw) { float magnitude = raw.magnitude; if (magnitude < stickDeadzone) return Vector2.zero; // 데드존 이후 0~1로 리매핑 float normalized = (magnitude - stickDeadzone) / (1f - stickDeadzone); normalized = Mathf.Clamp01(normalized); // 응답 곡선 적용 float curved = Mathf.Pow(normalized, stickExponent); return raw.normalized * curved; } private float CalculateSpeedMultiplier() { // LT와 RT가 동시에 눌리면 기본 속도 if (LeftTrigger > 0.1f && RightTrigger > 0.1f) return 1f; if (LeftTrigger > 0.1f) return Mathf.Lerp(1f, slowMultiplier, LeftTrigger); if (RightTrigger > 0.1f) return Mathf.Lerp(1f, boostMultiplier, RightTrigger); return 1f; } /// /// D-pad 플래그를 소비합니다. LateUpdate에서 읽은 후 호출해주세요. /// public void ConsumeDpad() { _dpadUp = false; _dpadDown = false; _dpadLeft = false; _dpadRight = false; } private void ResetAll() { LeftStick = Vector2.zero; RightStick = Vector2.zero; LeftTrigger = 0f; RightTrigger = 0f; SpeedMultiplier = 1f; ButtonSouthPressed = false; ButtonEastPressed = false; ButtonNorthPressed = false; ButtonWestPressed = false; LeftShoulderPressed = false; RightShoulderPressed = false; LeftShoulderHeld = false; RightShoulderHeld = false; StartPressed = false; _dpadUp = false; _dpadDown = false; _dpadLeft = false; _dpadRight = false; } }