Files
WhaleAdventure_VR_Diet/Assets/02_Scripts/Managers/GameClear.cs

149 lines
5.8 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
// 게임 클리어 시 처리:
// - NPC(오브젝트)들을 지정 위치로 재배치
// - 대화 존(DialogRegion)들을 활성/비활성 전환
// 리듬게임의 On Cleared 같은 UnityEvent에 OnGameClear()를 연결하면 한 번에 처리된다.
public class GameClear : MonoBehaviour
{
[SerializeField] private RoomClearGateController _clearGate;
// 옮길 오브젝트 ↔ 목적지(빈 Transform) 한 쌍
[System.Serializable]
public struct Relocation
{
public GameObject Target; // 옮길 오브젝트 (NPC 등)
public Transform Destination; // 옮길 위치/회전 기준
[Tooltip("체크하면 NavMeshAgent의 Base Offset을 아래 값으로 변경한다 (높이 조절용). NavMeshAgent가 없으면 무시됨.")]
public bool OverrideBaseOffset; // NavMeshAgent의 baseOffset을 바꿀지 여부
public float BaseOffset; // 적용할 baseOffset 값
}
// 클리어 시 적용할 존 상태 한 쌍
[System.Serializable]
public struct ZoneState
{
public DialogRegion Zone; // 대상 존
public bool Active; // 이 상태로 전환
}
[Header("NPC 재배치")]
[SerializeField] private List<Relocation> _relocations = new();
[Header("대화 존 상태")]
[SerializeField] private List<ZoneState> _zoneStates = new();
// ── 클리어 시 한 번에 (UnityEvent 연결용) ─────────────────────
public void OnGameClear()
{
if(_clearGate != null)
{
//_clearGate.OpenClearGate();
_clearGate.MarkRoomCleared();
}
Relocate();
ApplyZoneStates();
SetClearDialogParameter();
}
// ── NPC 재배치 ───────────────────────────────────────────────
// 리스트의 각 오브젝트를 지정 위치(위치+회전)로 이동.
public void Relocate()
{
foreach (var r in _relocations)
Relocate(r.Target, r.Destination, r.OverrideBaseOffset, r.BaseOffset);
}
// 단일 오브젝트 재배치(baseOffset 변경 없음). 기존 호출부 호환용 오버로드.
public void Relocate(GameObject target, Transform destination)
{
Relocate(target, destination, false, 0f);
}
// 단일 오브젝트 재배치. NavMeshAgent가 있으면 Warp로 옮겨야 경로/내부상태가 안 깨진다.
// NavMeshAgent는 (NavMesh 표면 높이 + baseOffset)으로 y가 강제되므로,
// 높이를 바꾸려면 destination.y가 아니라 baseOffset을 조정해야 한다.
public void Relocate(GameObject target, Transform destination, bool overrideBaseOffset, float baseOffset)
{
if (target == null || destination == null) return;
// 따라다니던 중이면 멈춰서 재배치 위치에 머물게 (다시 플레이어를 향해 가지 않도록)
if (target.TryGetComponent(out FollowObject follow) && follow.FollowEnabled)
follow.DisableFollow();
if (target.TryGetComponent(out NavMeshAgent agent) && agent.isOnNavMesh)
{
// 높이 조절: Warp 전에 baseOffset을 바꿔야 옮긴 위치에 바로 반영된다.
if (overrideBaseOffset)
agent.baseOffset = baseOffset;
Debug.Log($"엔드포지션 : {destination.position}");
agent.Warp(destination.position);
target.transform.rotation = destination.rotation;
Debug.Log($"이동한포지션 : {target.transform.position}");
}
else
{
target.transform.SetPositionAndRotation(destination.position, destination.rotation);
}
}
// ── 대화 존 활성/비활성 ──────────────────────────────────────
// 인스펙터에 설정한 _zoneStates를 한 번에 적용.
public void ApplyZoneStates()
{
foreach (var z in _zoneStates)
SetZoneActive(z.Zone, z.Active);
}
// 특정 존을 활성/비활성 (존 오브젝트째로 토글 → 트리거도 같이 꺼짐).
public void SetZoneActive(DialogRegion zone, bool active)
{
if (zone != null)
zone.gameObject.SetActive(active);
}
public void SetClearDialogParameter()
{
string sceneName1 = "블랙잭";
string sceneCode1 = "blackjack";
string sceneName2 = "캣룸";
string sceneCode2 = "CatsRoom";
if (RandomSceneRouteManager.Instance != null)
{
RandomSceneRouteManager.Instance.PrepareNextSceneChoices();
sceneName1 = RandomSceneRouteManager.Instance.GetNextSceneName1();
sceneCode1 = RandomSceneRouteManager.Instance.GetNextSceneCode1();
sceneName2 = RandomSceneRouteManager.Instance.GetNextSceneName2();
sceneCode2 = RandomSceneRouteManager.Instance.GetNextSceneCode2();
}
else
{
Debug.LogWarning("RandomSceneRouteManager가 없어서 테스트용 선택지를 사용합니다.");
}
DialogVariables.Set("SpaceSceneName1", sceneName1);
DialogVariables.Set("SpaceSceneCode1", sceneCode1);
DialogVariables.Set("SpaceSceneName2", sceneName2);
DialogVariables.Set("SpaceSceneCode2", sceneCode2);
if (_clearGate != null)
{
_clearGate.SetDoorChoices(sceneCode1, sceneCode2);
}
else
{
Debug.LogWarning("GameClear에 RoomClearGateController가 연결되지 않았습니다.");
}
Debug.Log($"선택지 세팅 완료: {sceneName1}/{sceneCode1}, {sceneName2}/{sceneCode2}");
}
}