using System.Collections; using UnityEngine; public class SpotlightFall : MonoBehaviour { [Header("떨어질 조명")] [SerializeField] private Transform spotlight; [Header("도착 위치")] [SerializeField] private Transform fallEndPoint; [Header("낙하 설정")] [SerializeField] private float fallDuration = 1f; [Header("충돌 사운드")] [SerializeField] private AudioSource impactAudioSource; [SerializeField] private AudioClip impactSound; [Range(0f, 1f)] [SerializeField] private float impactVolume = 1f; [Tooltip("조명이 도착하기 몇 초 전에 소리를 재생할지")] [SerializeField] private float impactSoundLeadTime = 0.12f; private Vector3 startPosition; private Quaternion startRotation; private bool hasFallen; private bool isFalling; private void Awake() { if (spotlight != null) { startPosition = spotlight.position; startRotation = spotlight.rotation; } } public void DropSpotlight() { if (hasFallen || isFalling) return; if (spotlight == null) { Debug.LogWarning( "[SpotlightFall] Spotlight가 연결되지 않았습니다." ); return; } if (fallEndPoint == null) { Debug.LogWarning( "[SpotlightFall] Fall End Point가 연결되지 않았습니다." ); return; } hasFallen = true; StartCoroutine(FallRoutine()); } private IEnumerator FallRoutine() { isFalling = true; Vector3 fallStartPosition = spotlight.position; Vector3 targetPosition = fallEndPoint.position; float duration = Mathf.Max(0.01f, fallDuration); float elapsed = 0f; bool impactSoundPlayed = false; while (elapsed < duration) { elapsed += Time.deltaTime; float t = Mathf.Clamp01(elapsed / duration); // 처음에는 느리고 아래로 갈수록 빠르게 낙하 float acceleratedT = t * t * t; spotlight.position = Vector3.Lerp( fallStartPosition, targetPosition, acceleratedT ); // 완전히 도착하기 조금 전에 와장창 소리 재생 if (!impactSoundPlayed && duration - elapsed <= impactSoundLeadTime) { impactSoundPlayed = true; PlayImpactSound(); } yield return null; } // 마지막 위치 정확히 맞추기 spotlight.position = targetPosition; // Lead Time이 너무 작아 소리가 실행되지 않았을 경우 대비 if (!impactSoundPlayed) { PlayImpactSound(); } isFalling = false; } private void PlayImpactSound() { if (impactAudioSource == null || impactSound == null) return; impactAudioSource.PlayOneShot( impactSound, impactVolume ); } public void ResetFall() { StopAllCoroutines(); hasFallen = false; isFalling = false; if (impactAudioSource != null) impactAudioSource.Stop(); if (spotlight != null) { spotlight.position = startPosition; spotlight.rotation = startRotation; } } [ContextMenu("Test Fall")] private void TestFall() { DropSpotlight(); } [ContextMenu("Reset Fall")] private void TestResetFall() { ResetFall(); } }