타이틀 타이밍
This commit is contained in:
133
Assets/02_Scripts/Intro/IntroBGMController.cs
Normal file
133
Assets/02_Scripts/Intro/IntroBGMController.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(AudioSource))]
|
||||
public class IntroBGMController : MonoBehaviour
|
||||
{
|
||||
[Header("Audio Source")]
|
||||
[SerializeField] private AudioSource audioSource;
|
||||
|
||||
[Header("Start Timing")]
|
||||
[SerializeField] private bool playOnStart = true;
|
||||
[SerializeField] private float startDelay = 0.5f;
|
||||
|
||||
[Header("Fade In")]
|
||||
[SerializeField] private bool useFadeIn = true;
|
||||
[SerializeField] private float fadeInDuration = 2.0f;
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float targetVolume = 0.55f;
|
||||
|
||||
[Header("Loop")]
|
||||
[SerializeField] private bool loop = true;
|
||||
|
||||
private Coroutine bgmRoutine;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (audioSource == null)
|
||||
{
|
||||
audioSource = GetComponent<AudioSource>();
|
||||
}
|
||||
|
||||
audioSource.playOnAwake = false;
|
||||
audioSource.loop = loop;
|
||||
audioSource.volume = 0f;
|
||||
audioSource.spatialBlend = 0f;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (playOnStart)
|
||||
{
|
||||
PlayBGM();
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayBGM()
|
||||
{
|
||||
if (audioSource == null || audioSource.clip == null)
|
||||
{
|
||||
Debug.LogWarning("[IntroBGMController] AudioSource 또는 AudioClip이 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bgmRoutine != null)
|
||||
{
|
||||
StopCoroutine(bgmRoutine);
|
||||
}
|
||||
|
||||
bgmRoutine = StartCoroutine(PlayBGMRoutine());
|
||||
}
|
||||
|
||||
private IEnumerator PlayBGMRoutine()
|
||||
{
|
||||
if (startDelay > 0f)
|
||||
{
|
||||
yield return new WaitForSeconds(startDelay);
|
||||
}
|
||||
|
||||
audioSource.volume = useFadeIn ? 0f : targetVolume;
|
||||
audioSource.loop = loop;
|
||||
audioSource.Play();
|
||||
|
||||
if (useFadeIn)
|
||||
{
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < fadeInDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / fadeInDuration);
|
||||
float easedT = EaseOutCubic(t);
|
||||
|
||||
audioSource.volume = Mathf.Lerp(0f, targetVolume, easedT);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
audioSource.volume = targetVolume;
|
||||
}
|
||||
|
||||
bgmRoutine = null;
|
||||
}
|
||||
|
||||
public void StopBGM(float fadeOutDuration = 1.0f)
|
||||
{
|
||||
if (audioSource == null)
|
||||
return;
|
||||
|
||||
if (bgmRoutine != null)
|
||||
{
|
||||
StopCoroutine(bgmRoutine);
|
||||
}
|
||||
|
||||
bgmRoutine = StartCoroutine(StopBGMRoutine(fadeOutDuration));
|
||||
}
|
||||
|
||||
private IEnumerator StopBGMRoutine(float fadeOutDuration)
|
||||
{
|
||||
float startVolume = audioSource.volume;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < fadeOutDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / fadeOutDuration);
|
||||
float easedT = EaseOutCubic(t);
|
||||
|
||||
audioSource.volume = Mathf.Lerp(startVolume, 0f, easedT);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
audioSource.volume = 0f;
|
||||
audioSource.Stop();
|
||||
|
||||
bgmRoutine = null;
|
||||
}
|
||||
|
||||
private float EaseOutCubic(float t)
|
||||
{
|
||||
return 1f - Mathf.Pow(1f - t, 3f);
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Intro/IntroBGMController.cs.meta
Normal file
2
Assets/02_Scripts/Intro/IntroBGMController.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 653843badaadbba42a66bae2168ac836
|
||||
222
Assets/02_Scripts/Intro/IntroTitleSequence.cs
Normal file
222
Assets/02_Scripts/Intro/IntroTitleSequence.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class IntroTitleSequence : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
public class IntroSequenceItem
|
||||
{
|
||||
[Header("Info")]
|
||||
public string itemName;
|
||||
|
||||
[Header("Target")]
|
||||
public GameObject target;
|
||||
|
||||
[Header("Timing")]
|
||||
public float delay = 0f;
|
||||
public float fadeDuration = 0.6f;
|
||||
|
||||
[Header("Appear Motion")]
|
||||
[Range(0.1f, 1f)]
|
||||
public float startScaleRatio = 0.92f;
|
||||
|
||||
public Vector3 startOffset = new Vector3(0f, -0.08f, 0f);
|
||||
|
||||
[Header("After Appear")]
|
||||
public bool enableFloatingAfterAppear = true;
|
||||
public bool enableParallaxAfterAppear = true;
|
||||
public bool enableButtonPulseAfterAppear = false;
|
||||
}
|
||||
|
||||
[Header("Sequence")]
|
||||
public bool playOnStart = true;
|
||||
public float globalDelayMultiplier = 1f;
|
||||
public float globalFadeMultiplier = 1f;
|
||||
public List<IntroSequenceItem> sequenceItems = new List<IntroSequenceItem>();
|
||||
|
||||
[Header("Optional Particle")]
|
||||
public ParticleSystem petalParticle;
|
||||
public float petalStartDelay = 0.2f;
|
||||
|
||||
private readonly Dictionary<GameObject, Vector3> originalPositions = new Dictionary<GameObject, Vector3>();
|
||||
private readonly Dictionary<GameObject, Vector3> originalScales = new Dictionary<GameObject, Vector3>();
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (playOnStart)
|
||||
{
|
||||
PlaySequence();
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaySequence()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
|
||||
CacheOriginalTransforms();
|
||||
PrepareAllItems();
|
||||
|
||||
StartCoroutine(PlaySequenceRoutine());
|
||||
}
|
||||
|
||||
private void CacheOriginalTransforms()
|
||||
{
|
||||
originalPositions.Clear();
|
||||
originalScales.Clear();
|
||||
|
||||
foreach (IntroSequenceItem item in sequenceItems)
|
||||
{
|
||||
if (item == null || item.target == null)
|
||||
continue;
|
||||
|
||||
originalPositions[item.target] = item.target.transform.localPosition;
|
||||
originalScales[item.target] = item.target.transform.localScale;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareAllItems()
|
||||
{
|
||||
foreach (IntroSequenceItem item in sequenceItems)
|
||||
{
|
||||
if (item == null || item.target == null)
|
||||
continue;
|
||||
|
||||
GameObject target = item.target;
|
||||
|
||||
target.SetActive(true);
|
||||
|
||||
Vector3 originalPosition = originalPositions[target];
|
||||
Vector3 originalScale = originalScales[target];
|
||||
|
||||
target.transform.localPosition = originalPosition + item.startOffset;
|
||||
target.transform.localScale = originalScale * item.startScaleRatio;
|
||||
|
||||
SetTargetAlpha(target, 0f);
|
||||
|
||||
SetOptionalMotionScripts(target, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlaySequenceRoutine()
|
||||
{
|
||||
if (petalParticle != null)
|
||||
{
|
||||
petalParticle.Stop();
|
||||
|
||||
if (petalStartDelay > 0f)
|
||||
yield return new WaitForSeconds(petalStartDelay);
|
||||
|
||||
petalParticle.Play();
|
||||
}
|
||||
|
||||
foreach (IntroSequenceItem item in sequenceItems)
|
||||
{
|
||||
if (item == null || item.target == null)
|
||||
continue;
|
||||
|
||||
StartCoroutine(AppearRoutine(item));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AppearRoutine(IntroSequenceItem item)
|
||||
{
|
||||
float delay = Mathf.Max(0f, item.delay * globalDelayMultiplier);
|
||||
float duration = Mathf.Max(0.01f, item.fadeDuration * globalFadeMultiplier);
|
||||
|
||||
if (delay > 0f)
|
||||
yield return new WaitForSeconds(delay);
|
||||
|
||||
GameObject target = item.target;
|
||||
|
||||
Vector3 originalPosition = originalPositions[target];
|
||||
Vector3 originalScale = originalScales[target];
|
||||
|
||||
Vector3 startPosition = originalPosition + item.startOffset;
|
||||
Vector3 startScale = originalScale * item.startScaleRatio;
|
||||
|
||||
target.transform.localPosition = startPosition;
|
||||
target.transform.localScale = startScale;
|
||||
SetTargetAlpha(target, 0f);
|
||||
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
float easedT = EaseOutCubic(t);
|
||||
|
||||
SetTargetAlpha(target, easedT);
|
||||
|
||||
target.transform.localPosition = Vector3.Lerp(startPosition, originalPosition, easedT);
|
||||
target.transform.localScale = Vector3.Lerp(startScale, originalScale, easedT);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SetTargetAlpha(target, 1f);
|
||||
target.transform.localPosition = originalPosition;
|
||||
target.transform.localScale = originalScale;
|
||||
|
||||
SetOptionalMotionScripts(
|
||||
target,
|
||||
item.enableFloatingAfterAppear,
|
||||
item.enableParallaxAfterAppear,
|
||||
item.enableButtonPulseAfterAppear
|
||||
);
|
||||
}
|
||||
|
||||
private void SetTargetAlpha(GameObject target, float alpha)
|
||||
{
|
||||
SpriteRenderer[] spriteRenderers = target.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
foreach (SpriteRenderer sr in spriteRenderers)
|
||||
{
|
||||
Color color = sr.color;
|
||||
color.a = alpha;
|
||||
sr.color = color;
|
||||
}
|
||||
|
||||
Graphic[] graphics = target.GetComponentsInChildren<Graphic>(true);
|
||||
foreach (Graphic graphic in graphics)
|
||||
{
|
||||
Color color = graphic.color;
|
||||
color.a = alpha;
|
||||
graphic.color = color;
|
||||
}
|
||||
|
||||
CanvasGroup[] canvasGroups = target.GetComponentsInChildren<CanvasGroup>(true);
|
||||
foreach (CanvasGroup canvasGroup in canvasGroups)
|
||||
{
|
||||
canvasGroup.alpha = alpha;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetOptionalMotionScripts(GameObject target, bool floating, bool parallax, bool buttonPulse)
|
||||
{
|
||||
IntroFloatingLayer[] floatingLayers = target.GetComponentsInChildren<IntroFloatingLayer>(true);
|
||||
foreach (IntroFloatingLayer layer in floatingLayers)
|
||||
{
|
||||
layer.enabled = floating;
|
||||
}
|
||||
|
||||
IntroParallaxLayer[] parallaxLayers = target.GetComponentsInChildren<IntroParallaxLayer>(true);
|
||||
foreach (IntroParallaxLayer layer in parallaxLayers)
|
||||
{
|
||||
layer.enabled = parallax;
|
||||
}
|
||||
|
||||
IntroButtonPulse[] buttonPulses = target.GetComponentsInChildren<IntroButtonPulse>(true);
|
||||
foreach (IntroButtonPulse pulse in buttonPulses)
|
||||
{
|
||||
pulse.enabled = buttonPulse;
|
||||
}
|
||||
}
|
||||
|
||||
private float EaseOutCubic(float t)
|
||||
{
|
||||
return 1f - Mathf.Pow(1f - t, 3f);
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Intro/IntroTitleSequence.cs.meta
Normal file
2
Assets/02_Scripts/Intro/IntroTitleSequence.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db9aafe58478a4b4ab17774501b5ef9d
|
||||
Reference in New Issue
Block a user