Files
Dino_Love_Simulation/Assets/02_Scripts/Story/ch4 scrip/SpotlightFall.cs
dldydtn9755-crypto dd4f318a9c 컴퓨터 설정까지
2026-07-28 14:08:45 +09:00

154 lines
3.6 KiB
C#

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();
}
}