Files
WhaleAdventure_VR/Assets/02_Scripts/Cave/RaftDamageReceiver.cs
2026-06-22 16:58:32 +09:00

156 lines
4.1 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class RaftDamageReceiver : MonoBehaviour
{
[Header("References")]
[SerializeField] private RaftHealth raftHealth;
[Header("Damage Cooldown")]
[SerializeField] private float sameObstacleDamageCooldown = 1.0f;
[SerializeField] private float globalDamageCooldown = 0.2f;
[Header("Haptic Feedback")]
[SerializeField] private bool useHapticFeedback = true;
[Range(0f, 1f)]
[SerializeField] private float hapticAmplitude = 0.6f;
[SerializeField] private float hapticDuration = 0.15f;
[Tooltip("체력 데미지 수치에 따라 햅틱 세기를 살짝 키웁니다.")]
[SerializeField] private bool scaleHapticByDamage = true;
[Header("Debug")]
[SerializeField] private bool showDebugLog = true;
private readonly Dictionary<DamageObstacle, float> lastDamageTimeByObstacle = new();
private float lastGlobalDamageTime = -999f;
private readonly List<InputDevice> hapticDevices = new();
private void Awake()
{
if (raftHealth == null)
{
raftHealth = GetComponentInParent<RaftHealth>();
}
if (raftHealth == null)
{
raftHealth = FindFirstObjectByType<RaftHealth>();
}
}
private void OnTriggerEnter(Collider other)
{
TryDamage(other);
}
private void OnTriggerStay(Collider other)
{
TryDamage(other);
}
private void TryDamage(Collider other)
{
if (raftHealth == null)
{
if (showDebugLog)
Debug.LogWarning("[RaftDamageReceiver] RaftHealth가 연결되지 않았습니다.", this);
return;
}
DamageObstacle obstacle = other.GetComponentInParent<DamageObstacle>();
if (obstacle == null)
return;
if (!obstacle.CanDamage)
return;
if (raftHealth.IsDead)
return;
float now = Time.time;
if (now < lastGlobalDamageTime + globalDamageCooldown)
return;
if (lastDamageTimeByObstacle.TryGetValue(obstacle, out float lastObstacleTime))
{
if (now < lastObstacleTime + sameObstacleDamageCooldown)
return;
}
int damage = obstacle.Damage;
if (damage <= 0)
return;
raftHealth.TakeDamage(damage);
lastGlobalDamageTime = now;
lastDamageTimeByObstacle[obstacle] = now;
PlayHaptic(damage);
if (showDebugLog)
{
Debug.Log($"[RaftDamageReceiver] {obstacle.name} 충돌. 데미지: {damage}");
}
}
private void PlayHaptic(int damage)
{
if (!useHapticFeedback)
return;
float amplitude = hapticAmplitude;
if (scaleHapticByDamage)
{
// 10 데미지 = 기본값, 15 이상 = 조금 더 강하게
float damageScale = Mathf.Clamp(damage / 10f, 1f, 1.5f);
amplitude *= damageScale;
}
amplitude = Mathf.Clamp01(amplitude);
SendHapticToDevice(XRNode.LeftHand, amplitude, hapticDuration);
SendHapticToDevice(XRNode.RightHand, amplitude, hapticDuration);
}
private void SendHapticToDevice(XRNode node, float amplitude, float duration)
{
InputDevice device = InputDevices.GetDeviceAtXRNode(node);
if (!device.isValid)
{
if (showDebugLog)
Debug.Log($"[RaftDamageReceiver] {node} 컨트롤러를 찾지 못했습니다.");
return;
}
if (!device.TryGetHapticCapabilities(out HapticCapabilities capabilities))
{
if (showDebugLog)
Debug.Log($"[RaftDamageReceiver] {node} 햅틱 기능을 확인할 수 없습니다.");
return;
}
if (!capabilities.supportsImpulse)
{
if (showDebugLog)
Debug.Log($"[RaftDamageReceiver] {node} 컨트롤러가 impulse 햅틱을 지원하지 않습니다.");
return;
}
device.SendHapticImpulse(0u, amplitude, duration);
}
}