게이트 이동 시스템 추가 및 기존 이동 매니저 정리

This commit is contained in:
dldydtn9755-crypto
2026-06-22 11:28:53 +09:00
parent f443c4a4de
commit 6fc20431e8
57 changed files with 767 additions and 435 deletions

View File

@@ -0,0 +1,326 @@
using System.Collections;
using UnityEngine;
public class RoomExitGate : MonoBehaviour
{
[Header("Gate Root")]
[SerializeField] private GameObject gateVisualRoot;
[Header("Door")]
[SerializeField] private Transform leftDoor;
[SerializeField] private Transform rightDoor;
[Header("Door Open Angle")]
[SerializeField] private float leftOpenAngleY = 110f;
[SerializeField] private float rightOpenAngleY = -110f;
[Header("Portal")]
[SerializeField] private GameObject portalEffectRoot;
[SerializeField] private ParticleSystem[] portalParticles;
[Header("Open Effect")]
[SerializeField] private ParticleSystem openParticle;
[SerializeField] private AudioSource openSound;
[Header("Trigger")]
[SerializeField] private Collider gateTrigger;
[Header("Timing")]
[SerializeField] private float openDelay = 1.2f;
[SerializeField] private float openDuration = 1.2f;
[SerializeField] private float portalShowDelay = 0.3f;
[Header("Player Check")]
[SerializeField] private string playerTag = "Player";
[Header("Scene Move")]
[SerializeField] private bool useRandomScene = true;
[SerializeField] private string fallbackSceneName;
[SerializeField] private float sceneMoveDelay = 0.2f;
[Header("Start Setting")]
[SerializeField] private bool hideGateOnStart = true;
[SerializeField] private bool hidePortalOnStart = true;
private Quaternion leftClosedRotation;
private Quaternion rightClosedRotation;
private Quaternion leftOpenRotation;
private Quaternion rightOpenRotation;
private bool isOpened = false;
private bool isOpening = false;
private bool isEntering = false;
private void Awake()
{
CacheDoorRotations();
AutoFindPortalParticles();
PrepareTrigger();
PrepareStartState();
}
private void CacheDoorRotations()
{
if (leftDoor != null)
{
leftClosedRotation = leftDoor.localRotation;
leftOpenRotation = leftClosedRotation * Quaternion.Euler(0f, leftOpenAngleY, 0f);
}
if (rightDoor != null)
{
rightClosedRotation = rightDoor.localRotation;
rightOpenRotation = rightClosedRotation * Quaternion.Euler(0f, rightOpenAngleY, 0f);
}
}
private void AutoFindPortalParticles()
{
if ((portalParticles == null || portalParticles.Length == 0) && portalEffectRoot != null)
{
portalParticles = portalEffectRoot.GetComponentsInChildren<ParticleSystem>(true);
}
}
private void PrepareTrigger()
{
if (gateTrigger != null)
{
gateTrigger.enabled = false;
gateTrigger.isTrigger = true;
}
Rigidbody rb = GetComponent<Rigidbody>();
if (rb == null)
{
rb = gameObject.AddComponent<Rigidbody>();
}
rb.isKinematic = true;
rb.useGravity = false;
}
private void PrepareStartState()
{
if (hideGateOnStart && gateVisualRoot != null)
{
gateVisualRoot.SetActive(false);
}
if (hidePortalOnStart && portalEffectRoot != null)
{
portalEffectRoot.SetActive(false);
}
}
public void OpenGate()
{
if (isOpened || isOpening)
{
return;
}
StartCoroutine(OpenGateRoutine());
}
private IEnumerator OpenGateRoutine()
{
isOpening = true;
if (openParticle != null)
{
openParticle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
openParticle.Play();
}
if (openSound != null)
{
openSound.Play();
}
yield return new WaitForSeconds(openDelay);
if (gateVisualRoot != null)
{
gateVisualRoot.SetActive(true);
}
float timer = 0f;
bool portalShown = false;
while (timer < openDuration)
{
timer += Time.deltaTime;
float t = Mathf.Clamp01(timer / openDuration);
t = Mathf.SmoothStep(0f, 1f, t);
if (leftDoor != null)
{
leftDoor.localRotation = Quaternion.Slerp(leftClosedRotation, leftOpenRotation, t);
}
if (rightDoor != null)
{
rightDoor.localRotation = Quaternion.Slerp(rightClosedRotation, rightOpenRotation, t);
}
if (!portalShown && timer >= portalShowDelay)
{
ShowPortal();
portalShown = true;
}
yield return null;
}
if (leftDoor != null)
{
leftDoor.localRotation = leftOpenRotation;
}
if (rightDoor != null)
{
rightDoor.localRotation = rightOpenRotation;
}
ShowPortal();
if (gateTrigger != null)
{
gateTrigger.enabled = true;
}
isOpened = true;
isOpening = false;
Debug.Log("게이트 열림 완료");
}
private void ShowPortal()
{
if (portalEffectRoot != null && !portalEffectRoot.activeSelf)
{
portalEffectRoot.SetActive(true);
}
if (portalParticles == null)
{
return;
}
foreach (ParticleSystem particle in portalParticles)
{
if (particle != null && !particle.isPlaying)
{
particle.Play();
}
}
}
private void OnTriggerEnter(Collider other)
{
if (!isOpened || isEntering)
{
return;
}
if (!IsPlayer(other))
{
return;
}
StartCoroutine(EnterGateRoutine());
}
private bool IsPlayer(Collider other)
{
if (other.CompareTag(playerTag))
{
return true;
}
if (other.transform.root.CompareTag(playerTag))
{
return true;
}
return false;
}
private IEnumerator EnterGateRoutine()
{
isEntering = true;
yield return new WaitForSeconds(sceneMoveDelay);
string nextSceneName = GetNextSceneName();
if (string.IsNullOrEmpty(nextSceneName))
{
Debug.LogWarning("다음 씬 이름이 비어있습니다.");
isEntering = false;
yield break;
}
if (SceneLoadManager.Instance == null)
{
Debug.LogError("SceneLoadManager가 없습니다.");
isEntering = false;
yield break;
}
Debug.Log("게이트 진입, 이동할 씬: " + nextSceneName);
SceneLoadManager.Instance.RequestSceneChange(nextSceneName);
}
private string GetNextSceneName()
{
if (useRandomScene && RandomSceneRouteManager.Instance != null)
{
return RandomSceneRouteManager.Instance.GetNextSceneName();
}
return fallbackSceneName;
}
public void CloseGateImmediately()
{
StopAllCoroutines();
isOpened = false;
isOpening = false;
isEntering = false;
if (leftDoor != null)
{
leftDoor.localRotation = leftClosedRotation;
}
if (rightDoor != null)
{
rightDoor.localRotation = rightClosedRotation;
}
if (portalEffectRoot != null)
{
portalEffectRoot.SetActive(false);
}
if (gateTrigger != null)
{
gateTrigger.enabled = false;
}
if (openParticle != null)
{
openParticle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
}
if (hideGateOnStart && gateVisualRoot != null)
{
gateVisualRoot.SetActive(false);
}
}
}