처음부분 추가
This commit is contained in:
117
Assets/02_Scripts/Story/EventZoneTimeline.cs
Normal file
117
Assets/02_Scripts/Story/EventZoneTimeline.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.XR.Interaction.Toolkit.Locomotion;
|
||||
|
||||
// 트리거 존(타임라인): Player 태그가 들어오면 등록된 타임라인을 재생.
|
||||
// 옵션으로 재생 동안 플레이어 로코모션(이동/회전)을 잠글 수 있다.
|
||||
// (UnityEvent를 실행하는 존은 EventZoneTrigger)
|
||||
[RequireComponent(typeof(Collider))]
|
||||
public class EventZoneTimeline : MonoBehaviour
|
||||
{
|
||||
[Tooltip("플레이어 진입 시 재생할 타임라인")]
|
||||
[SerializeField] private PlayableDirector _timeline;
|
||||
|
||||
[Tooltip("StoryState에 기록되는 Id. 비워두면 오브젝트 이름 사용 (DialogCondition의 RequiredZoneIds에서 참조)")]
|
||||
[SerializeField] private string _zoneId;
|
||||
|
||||
[Header("옵션")]
|
||||
[Tooltip("재생 동안 플레이어 조작(로코모션)을 잠글지 여부. HMD 트래킹은 유지된다")]
|
||||
[SerializeField] private bool _lockPlayerControl = true;
|
||||
|
||||
[Tooltip("한 번만 재생. 끄면 재생이 끝난 뒤 다시 들어오면 또 재생된다")]
|
||||
[SerializeField] private bool _playOnce = true;
|
||||
|
||||
private bool _hasPlayed;
|
||||
private bool _isPlaying;
|
||||
|
||||
// 어떤 EventZoneTimeline이든 타임라인(컷씬)이 재생 중이면 true.
|
||||
// 컷씬이 NPC의 루트를 직접 움직일 수 있으므로, 재생 중엔 대화 시작을 막는 데 쓴다.
|
||||
public static bool IsAnyPlaying => _playingCount > 0;
|
||||
private static int _playingCount;
|
||||
|
||||
// 존이 실제로 발동(기록)되는 순간 ZoneId와 함께 호출 (SceneBgm 등에서 구독)
|
||||
public static event Action<string> OnZoneTriggered;
|
||||
|
||||
public string ZoneId => string.IsNullOrEmpty(_zoneId) ? name : _zoneId;
|
||||
|
||||
// 잠글 때 켜져 있던 프로바이더만 기록해서, 해제 시 원래 꺼져 있던 것까지 켜지 않도록 한다.
|
||||
private readonly List<LocomotionProvider> _lockedProviders = new();
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
GetComponent<Collider>().isTrigger = true;
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (!other.CompareTag("Player")) return;
|
||||
|
||||
// 이어하기 로드 후에도 한 번 밟은 존은 다시 재생되지 않도록 StoryState 기록도 함께 본다.
|
||||
var story = StoryManager.Instance; // 매니저 없는 테스트 씬에서도 재생은 되도록 null 허용
|
||||
if (_isPlaying || (_playOnce && (_hasPlayed || (story != null && story.HasTriggeredZone(ZoneId)))))
|
||||
return;
|
||||
|
||||
// 밟은 사실은 대화 활성화 조건(RequiredZoneIds) 판정에 쓰이므로 타임라인 유무와 무관하게 기록
|
||||
if (story != null)
|
||||
story.RecordZoneTriggered(ZoneId);
|
||||
_hasPlayed = true;
|
||||
OnZoneTriggered?.Invoke(ZoneId);
|
||||
|
||||
if (_timeline == null)
|
||||
{
|
||||
Debug.LogWarning($"[EventZoneTimeline] 타임라인이 등록되지 않음 (기록만 됨): {name}");
|
||||
return;
|
||||
}
|
||||
|
||||
_isPlaying = true;
|
||||
_playingCount++;
|
||||
|
||||
if (_lockPlayerControl)
|
||||
LockPlayer(other.transform);
|
||||
|
||||
_timeline.stopped += OnTimelineStopped;
|
||||
_timeline.Play();
|
||||
}
|
||||
|
||||
// 타임라인이 끝(또는 외부에서 Stop)나면 호출됨. Extrapolation이 Hold면 stopped가 오지 않으니 None 권장.
|
||||
private void OnTimelineStopped(PlayableDirector director)
|
||||
{
|
||||
director.stopped -= OnTimelineStopped;
|
||||
if (_isPlaying) { _isPlaying = false; _playingCount--; }
|
||||
UnlockPlayer();
|
||||
}
|
||||
|
||||
// Player 태그 루트(XR Origin) 아래의 로코모션 프로바이더를 전부 꺼서 이동/회전을 막는다.
|
||||
private void LockPlayer(Transform playerRoot)
|
||||
{
|
||||
_lockedProviders.Clear();
|
||||
foreach (var provider in playerRoot.GetComponentsInChildren<LocomotionProvider>())
|
||||
{
|
||||
if (!provider.enabled) continue;
|
||||
provider.enabled = false;
|
||||
_lockedProviders.Add(provider);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnlockPlayer()
|
||||
{
|
||||
foreach (var provider in _lockedProviders)
|
||||
{
|
||||
if (provider != null)
|
||||
provider.enabled = true;
|
||||
}
|
||||
_lockedProviders.Clear();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_timeline != null)
|
||||
_timeline.stopped -= OnTimelineStopped;
|
||||
|
||||
// 존이 재생 중에 파괴돼도 전역 카운트/플레이어 잠금이 남지 않도록
|
||||
if (_isPlaying) { _isPlaying = false; _playingCount--; }
|
||||
UnlockPlayer();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user