using UnityEngine; using UnityEngine.InputSystem; // Input Systemを使うために必要 using UnityEngine.XR; // 振動機能のために必要 [RequireComponent(typeof(Collider))] [RequireComponent(typeof(Rigidbody))] public class VRInputPunch : MonoBehaviour { [SerializeField] private InputActionProperty velocityAction; [SerializeField] private XRNode controllerNode = XRNode.RightHand; [SerializeField] private VRInputPoseDetector poseDetector; [Header("攻撃(パンチ)設定")] [SerializeField] private float minPunchSpeed = 1.0f; // パンチとして判定する最低速度 (m/s) [SerializeField] private float damageMultiplier = 10.0f; // ダメージ倍率 [SerializeField] private float hapticAmplitude = 0.5f; // 通常ヒットの振動の強さ [SerializeField] private float hapticDuration = 0.1f; // 通常ヒットの振動の長さ [Header("パリィ設定")] [SerializeField] private float parryStunDuration = 3.0f; // スタン時間(秒) [SerializeField] private float parryHapticAmplitude = 0.9f; // パリィ成功時の振動の強さ [SerializeField] private float parryHapticDuration = 0.25f; // パリィ成功時の振動の長さ // ─── 多段ヒット・連続暴発防止用タイマー ─── private float punchHitCooldown = 0f; // 次のパンチが当たるまでのインターバル private float parryTriggerCooldown = 0f; // 次のパリィが成功するまでのインターバル private void OnEnable() { if (velocityAction.action != null) { velocityAction.action.Enable(); } } private void OnDisable() { if (velocityAction.action != null) { velocityAction.action.Disable(); } } void Start() { Rigidbody rb = GetComponent(); rb.isKinematic = true; rb.useGravity = false; GetComponent().isTrigger = true; } private void OnTriggerEnter(Collider other) { // コントローラーの現在の移動速度を取得 Vector3 velocity = velocityAction.action.ReadValue(); float speed = velocity.magnitude; // ======================================================================== // 【パリィ判定】当たったオブジェクトが敵の拳だった場合 // ======================================================================== if (other.CompareTag("EnemyFist")) { Debug.Log($"🛡️ [パリィチェック] 敵の拳と接触。構え状態: {poseDetector.IsPosing}"); // 自分が「構え状態」のときだけパリィの成立チェックを行う if (poseDetector.IsPosing) { // 1. ザコ敵(EnemyAI)へのパリィ判定 EnemyAI enemyAI = other.GetComponentInParent(); if (enemyAI != null) { enemyAI.TriggerParryStun(parryStunDuration); TriggerHaptics(parryHapticAmplitude, parryHapticDuration); Debug.Log($"🛡️ 【ジャストパリィ成功!】 敵の体勢を崩しました。"); return; // ★本当のパリィ成功時のみ、ここで処理を終了する } // 2. ボス(BossController)へのパリィ判定 BossController boss = other.GetComponentInParent(); if (boss != null) { // ★リファクタリング:ボスが本当に攻撃中(Bite/Charge)で、パリィが成功した時だけ終了する if (boss.TriggerParryStun()) { TriggerHaptics(parryHapticAmplitude, parryHapticDuration); Debug.Log("🛡️ 【ジャストパリィ成功!】 ボスの体勢を崩しました!"); return; // ★本当のパリィ成功時のみ、ここで処理を終了する } } } // ─── ★ここが今回の核心(超重要リファクタリング) ─── // 構え状態ではなかった場合、またはボスが攻撃中でなくパリィが不成立だった場合は、 // 「プレイヤーが隙を狙って殴りに行った」とみなして、returnせずにそのまま下のパンチ処理へ流す! Debug.Log("🥊 パリィ不成立、または攻撃チャンス:通常のパンチダメージ処理へ移行します。"); } // ──────────────────────────────────────────────────────────────────────── // ======================================================================== // 【パンチ攻撃の処理】 // ======================================================================== Debug.Log($"[InputSystem接触] {other.name} に触れました。センサー速度: {speed:F2} m/s"); if (speed >= minPunchSpeed) { IDamageble damageble = other.GetComponentInParent(); if (damageble != null) { DamageInfo info = new DamageInfo(); // 構えからパンチするとダメージ2倍、ゲージ取得度2倍 if (poseDetector.IsPosing) { info.amount = (speed * damageMultiplier) * 2f; info.isPoseBonus = true; if (PlayerStatusManager.Instance != null) PlayerStatusManager.Instance.AddGauge(20f); } else { info.amount = speed * damageMultiplier; info.isPoseBonus = false; if (PlayerStatusManager.Instance != null) PlayerStatusManager.Instance.AddGauge(10f); } info.hitPosition = other.transform.position; info.punchDirection = velocity.normalized; if (PlayerStatusManager.Instance != null) { info.amount *= PlayerStatusManager.Instance.CurrentAttackMultiplier; } damageble.TakeDamage(info); Debug.Log($"パンチ成功 ダメージ: {info.amount:F1}"); // 通常ヒットの振動を発生 TriggerHaptics(hapticAmplitude, hapticDuration); } } else { Debug.Log($"スピードが足りません。必要: {minPunchSpeed} / 現在: {speed:F2}"); } } /// 引数に応じて指定された強さと長さでコントローラーを振動させる private void TriggerHaptics(float amplitude, float duration) { UnityEngine.XR.InputDevice device = InputDevices.GetDeviceAtXRNode(controllerNode); if (device.isValid) { device.SendHapticImpulse(0, amplitude, duration); } } }