조개 사운드

This commit is contained in:
2026-06-24 14:40:39 +09:00
parent 59bf6f0555
commit 513fa94ab9
28 changed files with 626 additions and 4 deletions

View File

@@ -38,6 +38,36 @@ public class ClamOpenClose : MonoBehaviour
[Tooltip("쾅 하고 닫힌 뒤 원래 닫힌 위치로 돌아오는 시간입니다.")]
[SerializeField] private float snapCloseOvershootDuration = 0.02f;
[Header("Sound")]
[SerializeField] private AudioSource audioSource;
[Tooltip("조개가 닫히며 입이 부딪힐 때 재생할 사운드입니다. 여러 개를 넣으면 랜덤 재생됩니다.")]
[SerializeField] private AudioClip[] closeImpactSounds;
[Tooltip("조개가 닫히기 시작할 때 재생할 예고/마찰 사운드입니다. 필요 없으면 비워두세요.")]
[SerializeField] private AudioClip closeStartSound;
[Range(0f, 1f)]
[SerializeField] private float closeImpactVolume = 1f;
[Range(0f, 1f)]
[SerializeField] private float closeStartVolume = 0.5f;
[Tooltip("닫힘 충격음의 최소 피치입니다.")]
[SerializeField] private float minImpactPitch = 0.9f;
[Tooltip("닫힘 충격음의 최대 피치입니다.")]
[SerializeField] private float maxImpactPitch = 1.1f;
[Tooltip("닫힘 충격음의 볼륨을 살짝 랜덤하게 줄지 여부입니다.")]
[SerializeField] private bool randomizeImpactVolume = true;
[Tooltip("볼륨 랜덤 적용 시 최소 배율입니다.")]
[SerializeField] private float minImpactVolumeMultiplier = 0.85f;
[Tooltip("볼륨 랜덤 적용 시 최대 배율입니다.")]
[SerializeField] private float maxImpactVolumeMultiplier = 1.0f;
[Header("Start Option")]
[SerializeField] private bool startAutomatically = true;
[SerializeField] private bool startOpened = false;
@@ -74,6 +104,17 @@ private void Awake()
if (found != null) downShell = found;
}
if (audioSource == null)
{
audioSource = GetComponent<AudioSource>();
}
if (audioSource != null)
{
audioSource.playOnAwake = false;
audioSource.loop = false;
}
if (upShell == null)
{
Debug.LogWarning("[ClamOpenClose] UpShell이 연결되지 않았습니다.", this);
@@ -145,6 +186,7 @@ private IEnumerator OpenCloseRoutine()
yield return new WaitForSeconds(openWait);
isClosing = true;
PlayCloseStartSound();
onCloseStarted?.Invoke();
yield return MoveShells(
@@ -158,6 +200,10 @@ private IEnumerator OpenCloseRoutine()
isOpen = false;
// 실제 입이 맞닿는 타이밍.
// 랜덤으로 닫혀도 항상 닫힘 동작이 끝난 직후 실행됨.
PlayCloseImpactSound();
if (useSnapClose)
{
yield return SnapCloseEffect();
@@ -225,6 +271,47 @@ private IEnumerator SnapCloseEffect()
downShell.localRotation = downClosedRot;
}
private void PlayCloseStartSound()
{
if (audioSource == null || closeStartSound == null)
return;
audioSource.pitch = 1f;
audioSource.PlayOneShot(closeStartSound, closeStartVolume);
}
private void PlayCloseImpactSound()
{
if (audioSource == null)
return;
if (closeImpactSounds == null || closeImpactSounds.Length == 0)
return;
AudioClip clip = closeImpactSounds[Random.Range(0, closeImpactSounds.Length)];
if (clip == null)
return;
float originalPitch = audioSource.pitch;
audioSource.pitch = Random.Range(minImpactPitch, maxImpactPitch);
float volume = closeImpactVolume;
if (randomizeImpactVolume)
{
float volumeMultiplier = Random.Range(minImpactVolumeMultiplier, maxImpactVolumeMultiplier);
volume *= volumeMultiplier;
}
audioSource.PlayOneShot(clip, volume);
// PlayOneShot은 재생 직후 피치를 바꿔도 이미 재생 중인 소리에 영향이 적지만,
// 다음 사운드 재생을 위해 기본 피치로 복구.
audioSource.pitch = originalPitch;
}
private void SetClosedImmediately()
{
if (upShell != null)