- GameOverUI: 게임 오버 화면 표시 - VictoryUI: 보스 처치 시 승리 화면 표시 - VictoryEffect: 슬로우 모션, 카메라 연출, 이펙트 재생 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
188 lines
5.2 KiB
C#
188 lines
5.2 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using Colosseum.Enemy;
|
|
|
|
namespace Colosseum.Effects
|
|
{
|
|
/// <summary>
|
|
/// 보스 승리 연출 이펙트.
|
|
/// 보스 사망 시 카메라 연출, 이펙트, 슬로우 모션 등을 처리합니다.
|
|
/// GameManager에 의해 활성화됩니다.
|
|
/// </summary>
|
|
public class VictoryEffect : MonoBehaviour
|
|
{
|
|
[Header("Victory Settings")]
|
|
[Tooltip("승리 시 슬로우 모션 배율")]
|
|
[SerializeField] private float slowMotionScale = 0.3f;
|
|
|
|
[Tooltip("슬로우 모션 지속 시간")]
|
|
[SerializeField] private float slowMotionDuration = 2f;
|
|
|
|
[Header("Effects")]
|
|
[Tooltip("승리 시 생성할 이펙트 프리팹")]
|
|
[SerializeField] private GameObject victoryEffectPrefab;
|
|
|
|
[Tooltip("이펙트 생성 위치 오프셋")]
|
|
[SerializeField] private Vector3 effectOffset = Vector3.up * 2f;
|
|
|
|
[Header("Audio")]
|
|
[Tooltip("승리 사운드")]
|
|
[SerializeField] private AudioClip victorySound;
|
|
|
|
[Tooltip("사운드 볼륨")]
|
|
[SerializeField] private float soundVolume = 1f;
|
|
|
|
[Header("Debug")]
|
|
[SerializeField] private bool debugMode = true;
|
|
|
|
// 상태
|
|
private bool isPlaying = false;
|
|
private float originalTimeScale;
|
|
private Camera mainCamera;
|
|
|
|
private void Awake()
|
|
{
|
|
mainCamera = Camera.main;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
PlayVictoryEffect();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
// 시간 스케일 복구
|
|
if (isPlaying)
|
|
{
|
|
Time.timeScale = 1f;
|
|
isPlaying = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 승리 연출 재생
|
|
/// </summary>
|
|
public void PlayVictoryEffect()
|
|
{
|
|
if (isPlaying) return;
|
|
|
|
StartCoroutine(VictorySequence());
|
|
}
|
|
|
|
private IEnumerator VictorySequence()
|
|
{
|
|
isPlaying = true;
|
|
originalTimeScale = Time.timeScale;
|
|
|
|
if (debugMode)
|
|
{
|
|
Debug.Log("[VictoryEffect] Starting victory sequence");
|
|
}
|
|
|
|
// 1. 슬로우 모션
|
|
yield return StartCoroutine(PlaySlowMotion());
|
|
|
|
// 2. 카메라 연출
|
|
yield return StartCoroutine(PlayCameraEffect());
|
|
|
|
// 3. 이펙트 생성
|
|
SpawnVictoryEffect();
|
|
|
|
// 4. 사운드 재생
|
|
PlayVictorySound();
|
|
|
|
// 5. 시간 복구
|
|
Time.timeScale = originalTimeScale;
|
|
isPlaying = false;
|
|
|
|
if (debugMode)
|
|
{
|
|
Debug.Log("[VictoryEffect] Victory sequence complete");
|
|
}
|
|
}
|
|
|
|
private IEnumerator PlaySlowMotion()
|
|
{
|
|
float elapsed = 0f;
|
|
|
|
while (elapsed < slowMotionDuration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
float t = elapsed / slowMotionDuration;
|
|
|
|
// 처음에는 슬로우, 나중에는 복구
|
|
if (t < 0.5f)
|
|
{
|
|
Time.timeScale = Mathf.Lerp(originalTimeScale, slowMotionScale, t * 2f);
|
|
}
|
|
else
|
|
{
|
|
Time.timeScale = Mathf.Lerp(slowMotionScale, originalTimeScale, (t - 0.5f) * 2f);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
Time.timeScale = slowMotionScale;
|
|
}
|
|
|
|
private IEnumerator PlayCameraEffect()
|
|
{
|
|
if (mainCamera == null || BossEnemy.ActiveBoss == null)
|
|
yield break;
|
|
|
|
// 보스 위치로 카메라 이동
|
|
Transform bossTransform = BossEnemy.ActiveBoss.transform;
|
|
Vector3 targetPosition = bossTransform.position + effectOffset;
|
|
|
|
float elapsed = 0f;
|
|
float duration = slowMotionDuration * 0.5f;
|
|
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
|
|
// 카메라가 보스를 바라보도록
|
|
mainCamera.transform.LookAt(targetPosition);
|
|
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
private void SpawnVictoryEffect()
|
|
{
|
|
if (victoryEffectPrefab == null) return;
|
|
|
|
Vector3 spawnPosition = transform.position + effectOffset;
|
|
|
|
if (BossEnemy.ActiveBoss != null)
|
|
{
|
|
spawnPosition = BossEnemy.ActiveBoss.transform.position + effectOffset;
|
|
}
|
|
|
|
var effect = Instantiate(victoryEffectPrefab, spawnPosition, Quaternion.identity);
|
|
|
|
// 일정 시간 후 제거
|
|
Destroy(effect, 5f);
|
|
|
|
if (debugMode)
|
|
{
|
|
Debug.Log("[VictoryEffect] Spawned victory effect");
|
|
}
|
|
}
|
|
|
|
private void PlayVictorySound()
|
|
{
|
|
if (victorySound == null) return;
|
|
|
|
AudioSource.PlayClipAtPoint(victorySound, transform.position, soundVolume);
|
|
|
|
if (debugMode)
|
|
{
|
|
Debug.Log("[VictoryEffect] Played victory sound");
|
|
}
|
|
}
|
|
}
|
|
}
|