using UnityEngine; using UnityEngine.XR.Interaction.Toolkit.Locomotion; using UnityEngine.InputSystem.XR; public class PlayerController : MonoBehaviour { // 시야 가림용 구체(Sight)가 쓰는 머티리얼 — 알파 0(투명)이면 정상 시야, 1(불투명)이면 암전 [SerializeField] private Material _sightMat; [SerializeField] private GameObject _bloodDieImgRef; [SerializeField] private AudioClip _bloodSfx; private static readonly int _baseColorId = Shader.PropertyToID("_BaseColor"); private static readonly int _colorId = Shader.PropertyToID("_Color"); private void Awake() { // 머티리얼 에셋을 직접 수정하므로 이전 씬에서 암전된 알파가 남아 넘어올 수 있다 — 씬 시작은 항상 투명 SetSightAlpha(0f); } // onoff=true: 시야 복구(투명하게), false: 시야 암전(불투명하게). 완료 시점이 필요하면 await 가능. public async Awaitable FadeSight(bool onoff, float duration) { if (_sightMat == null) { Debug.LogWarning("[PlayerController] _sightMat이 비어 있어 시야 페이드를 건너뜁니다."); return; } float start = _sightMat.GetColor(AlphaProp).a; float end = onoff ? 0f : 1f; float timer = 0f; while (timer < duration) { timer += Time.deltaTime; SetSightAlpha(Mathf.Lerp(start, end, Mathf.Clamp01(timer / duration))); await Awaitable.NextFrameAsync(destroyCancellationToken); } SetSightAlpha(end); } // URP 셰이더는 _BaseColor, 레거시/커스텀 셰이더는 _Color를 쓴다 private int AlphaProp => _sightMat.HasProperty(_baseColorId) ? _baseColorId : _colorId; private void SetSightAlpha(float alpha) { if (_sightMat == null) return; Color color = _sightMat.GetColor(AlphaProp); color.a = alpha; _sightMat.SetColor(AlphaProp, color); } public void PlayerBloodDie(float duration) { _ = Util.RunDelayed(duration, () => { StopPlayerMovement(); // XR 이동/회전 정지 — PauseAllAnimations로는 못 막는다 LocalManager.PauseAllAnimations(); _bloodDieImgRef.SetActive(true); SoundManager.Instance.PlaySFX(_bloodSfx); },this.destroyCancellationToken); } // Player 태그 루트(XR Origin) 아래에서 플레이어가 시야/위치를 바꾸는 수단을 전부 정지시킨다: // 1) LocomotionProvider → 이동/회전(중력 포함) // 2) TrackedPoseDriver → 헤드셋·컨트롤러 트래킹. 카메라 드라이버를 꺼야 머리를 돌려도 시야가 안 돈다 // PauseAllAnimations는 Animator/타임라인/파티클만 멈추므로 이 둘은 못 막는다. 사망 연출이라 복구하지 않는다. private static void StopPlayerMovement() { var playerRoot = GameObject.FindWithTag("Player"); if (playerRoot == null) { Debug.LogWarning("[PlayerController] 'Player' 태그 루트를 찾지 못해 이동 정지를 건너뜁니다."); return; } // 이동/회전(로코모션) foreach (var provider in playerRoot.GetComponentsInChildren(true)) provider.enabled = false; // 헤드셋/컨트롤러 트래킹 — 실제 포즈를 매 프레임 카메라/손에 적용하는 드라이버를 꺼 시야를 고정. // (컨트롤러 손도 함께 멈춘다. 카메라만 얼리려면 Camera.main의 드라이버만 끄면 됨) foreach (var driver in playerRoot.GetComponentsInChildren(true)) driver.enabled = false; } }