육지도착

This commit is contained in:
2026-06-22 16:58:32 +09:00
parent f7a71e11d6
commit 74afff5be8
23 changed files with 1500 additions and 54 deletions

View File

@@ -0,0 +1,160 @@
using System.Collections.Generic;
using UnityEngine;
public class ClamBiteDetector : MonoBehaviour
{
[Header("References")]
[SerializeField] private ClamOpenClose clam;
[SerializeField] private RaftHealth health;
[SerializeField] private MemoryFragmentReset memoryFragment;
[Header("Bite Damage")]
[SerializeField] private int biteDamage = 20;
[Header("Bite Zone")]
[SerializeField] private Collider biteZoneCollider;
[Tooltip("조개가 닫히는 동안 이미 한 번 물렸으면 추가 판정을 막습니다.")]
[SerializeField] private bool biteOncePerClose = true;
[Header("Target Tags")]
[SerializeField] private string handTag = "PlayerHand";
[SerializeField] private string fragmentTag = "MemoryFragment";
[Header("Debug")]
[SerializeField] private bool showDebugLog = true;
private bool hasBittenThisClose;
private readonly HashSet<Collider> collidersInside = new();
private void Awake()
{
if (biteZoneCollider == null)
biteZoneCollider = GetComponent<Collider>();
if (biteZoneCollider != null)
{
biteZoneCollider.isTrigger = true;
biteZoneCollider.enabled = false;
}
if (clam == null)
clam = GetComponentInParent<ClamOpenClose>();
if (health == null)
health = FindFirstObjectByType<RaftHealth>();
if (memoryFragment == null)
memoryFragment = FindFirstObjectByType<MemoryFragmentReset>();
}
private void OnEnable()
{
if (clam != null)
{
clam.onCloseStarted.AddListener(EnableBiteWindow);
clam.onClosed.AddListener(DisableBiteWindow);
clam.onOpened.AddListener(ResetBiteState);
}
}
private void OnDisable()
{
if (clam != null)
{
clam.onCloseStarted.RemoveListener(EnableBiteWindow);
clam.onClosed.RemoveListener(DisableBiteWindow);
clam.onOpened.RemoveListener(ResetBiteState);
}
}
private void OnTriggerEnter(Collider other)
{
collidersInside.Add(other);
if (IsBiteWindowOpen())
TryBite(other);
}
private void OnTriggerStay(Collider other)
{
collidersInside.Add(other);
if (IsBiteWindowOpen())
TryBite(other);
}
private void OnTriggerExit(Collider other)
{
collidersInside.Remove(other);
}
private void EnableBiteWindow()
{
hasBittenThisClose = false;
if (biteZoneCollider != null)
biteZoneCollider.enabled = true;
if (showDebugLog)
Debug.Log("[ClamBiteDetector] 조개 물림 판정 ON", this);
foreach (Collider col in collidersInside)
{
if (col != null)
TryBite(col);
}
}
private void DisableBiteWindow()
{
if (biteZoneCollider != null)
biteZoneCollider.enabled = false;
collidersInside.Clear();
if (showDebugLog)
Debug.Log("[ClamBiteDetector] 조개 물림 판정 OFF", this);
}
private void ResetBiteState()
{
hasBittenThisClose = false;
}
private bool IsBiteWindowOpen()
{
if (biteZoneCollider == null)
return false;
return biteZoneCollider.enabled;
}
private void TryBite(Collider other)
{
if (other == null)
return;
if (biteOncePerClose && hasBittenThisClose)
return;
bool isHand = other.CompareTag(handTag) || other.GetComponentInParent<XRHandMarker>() != null;
bool isFragment = other.CompareTag(fragmentTag) || other.GetComponentInParent<MemoryFragmentReset>() != null;
if (!isHand && !isFragment)
return;
hasBittenThisClose = true;
if (health != null)
health.TakeDamage(biteDamage);
if (memoryFragment != null)
memoryFragment.ResetFragment();
if (showDebugLog)
{
Debug.Log($"[ClamBiteDetector] 조개에게 물림. 데미지 {biteDamage}, 기억의 조각 리셋", this);
}
}
}