266 lines
7.9 KiB
C#
266 lines
7.9 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
public class RoomEnterHandler : MonoBehaviour
|
|
{
|
|
[Serializable]
|
|
public class RoomTarget
|
|
{
|
|
public string roomId;
|
|
public Transform spawnPoint;
|
|
public GameObject roomRoot;
|
|
public UnityEvent onEnter;
|
|
}
|
|
|
|
[Header("Enter Mode")]
|
|
[Tooltip("켜면 RoomData의 Scene Name으로 씬을 이동합니다. 끄면 같은 씬 안에서 위치 이동/방 오브젝트 활성화를 합니다.")]
|
|
[SerializeField] private bool useSceneLoading = false;
|
|
|
|
[Header("Same Scene Movement")]
|
|
[SerializeField] private Transform playerRoot;
|
|
[SerializeField] private bool deactivateOtherRoomRoots = false;
|
|
[SerializeField] private List<RoomTarget> roomTargets = new List<RoomTarget>();
|
|
|
|
[Header("UI")]
|
|
[SerializeField] private GameObject roomSelectRoot;
|
|
[SerializeField] private bool hideRoomSelectOnEnter = true;
|
|
|
|
[Header("Room Enter Message UI")]
|
|
[Tooltip("방 입장 메시지 패널입니다.")]
|
|
[SerializeField] private GameObject roomEnterMessagePanel;
|
|
|
|
[Tooltip("방 입장 메시지를 표시할 TextMeshProUGUI입니다.")]
|
|
[SerializeField] private TextMeshProUGUI roomEnterMessageText;
|
|
|
|
[Tooltip("방 입장 메시지 전체 Root입니다. 보통 RoomEnterMessageCanvas를 넣습니다.")]
|
|
[SerializeField] private Transform roomEnterMessageRoot;
|
|
|
|
[Tooltip("메시지가 화면에 표시되는 시간입니다.")]
|
|
[SerializeField] private float roomEnterMessageDuration = 2f;
|
|
|
|
[Tooltip("{0} 자리에 RoomData의 RoomName이 들어갑니다.")]
|
|
[SerializeField] private string roomEnterMessageFormat = "{0}에 입장했습니다";
|
|
|
|
[Header("Room Enter Message Position")]
|
|
[Tooltip("메시지를 기준으로 배치할 카메라입니다. XR Origin > Camera Offset > Main Camera를 넣으세요.")]
|
|
[SerializeField] private Transform messageCameraTarget;
|
|
|
|
[Tooltip("켜면 방 입장 메시지가 카메라 앞쪽으로 자동 이동합니다.")]
|
|
[SerializeField] private bool placeMessageInFrontOfCamera = true;
|
|
|
|
[Tooltip("카메라 앞 몇 m 위치에 메시지를 띄울지 정합니다.")]
|
|
[SerializeField] private float messageDistance = 1.6f;
|
|
|
|
[Tooltip("월드 기준 위/아래 위치 보정값입니다. 양수면 위로 올라갑니다.")]
|
|
[SerializeField] private float messageHeightOffset = 0.25f;
|
|
|
|
[Tooltip("글자가 뒤집혀 보이면 켜세요.")]
|
|
[SerializeField] private bool flipMessageRotation = false;
|
|
|
|
[Header("Events")]
|
|
public UnityEvent onAnyRoomEntered;
|
|
|
|
private Coroutine roomEnterMessageCoroutine;
|
|
|
|
private void Awake()
|
|
{
|
|
if (messageCameraTarget == null && Camera.main != null)
|
|
{
|
|
messageCameraTarget = Camera.main.transform;
|
|
}
|
|
|
|
if (roomEnterMessagePanel != null)
|
|
{
|
|
roomEnterMessagePanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
public void EnterRoom(RoomData roomData)
|
|
{
|
|
if (roomData == null)
|
|
{
|
|
Debug.LogWarning($"[{nameof(RoomEnterHandler)}] RoomData가 없습니다.");
|
|
return;
|
|
}
|
|
|
|
if (hideRoomSelectOnEnter && roomSelectRoot != null)
|
|
{
|
|
roomSelectRoot.SetActive(false);
|
|
}
|
|
|
|
if (useSceneLoading)
|
|
{
|
|
EnterRoomByScene(roomData);
|
|
}
|
|
else
|
|
{
|
|
EnterRoomInSameScene(roomData);
|
|
}
|
|
|
|
onAnyRoomEntered?.Invoke();
|
|
}
|
|
|
|
private void EnterRoomByScene(RoomData roomData)
|
|
{
|
|
if (!roomData.HasSceneName())
|
|
{
|
|
Debug.LogWarning($"[{nameof(RoomEnterHandler)}] Scene Name이 비어 있습니다: {roomData.RoomName}");
|
|
return;
|
|
}
|
|
|
|
SceneManager.LoadScene(roomData.SceneName);
|
|
}
|
|
|
|
private void EnterRoomInSameScene(RoomData roomData)
|
|
{
|
|
RoomTarget target = FindTarget(roomData.RoomId);
|
|
|
|
if (target == null)
|
|
{
|
|
Debug.Log($"[{nameof(RoomEnterHandler)}] 방 입장 테스트: {roomData.RoomName} / roomId: {roomData.RoomId}");
|
|
return;
|
|
}
|
|
|
|
if (deactivateOtherRoomRoots)
|
|
{
|
|
foreach (RoomTarget roomTarget in roomTargets)
|
|
{
|
|
if (roomTarget != null && roomTarget.roomRoot != null)
|
|
{
|
|
roomTarget.roomRoot.SetActive(roomTarget == target);
|
|
}
|
|
}
|
|
}
|
|
else if (target.roomRoot != null)
|
|
{
|
|
target.roomRoot.SetActive(true);
|
|
}
|
|
|
|
if (playerRoot != null && target.spawnPoint != null)
|
|
{
|
|
CharacterController controller = playerRoot.GetComponent<CharacterController>();
|
|
bool hadController = controller != null;
|
|
|
|
if (hadController)
|
|
{
|
|
controller.enabled = false;
|
|
}
|
|
|
|
playerRoot.SetPositionAndRotation(target.spawnPoint.position, target.spawnPoint.rotation);
|
|
|
|
if (hadController)
|
|
{
|
|
controller.enabled = true;
|
|
}
|
|
}
|
|
|
|
target.onEnter?.Invoke();
|
|
|
|
ShowRoomEnterMessage(roomData);
|
|
|
|
Debug.Log($"[{nameof(RoomEnterHandler)}] 방 입장: {roomData.RoomName}");
|
|
}
|
|
|
|
private RoomTarget FindTarget(string roomId)
|
|
{
|
|
return roomTargets.Find(target => target != null && target.roomId == roomId);
|
|
}
|
|
|
|
private void ShowRoomEnterMessage(RoomData roomData)
|
|
{
|
|
if (roomData == null)
|
|
return;
|
|
|
|
if (roomEnterMessagePanel == null || roomEnterMessageText == null)
|
|
return;
|
|
|
|
if (roomEnterMessageRoot != null)
|
|
{
|
|
roomEnterMessageRoot.gameObject.SetActive(true);
|
|
}
|
|
|
|
PlaceRoomEnterMessageInFrontOfCamera();
|
|
|
|
string roomName = roomData.RoomName;
|
|
roomEnterMessageText.text = string.Format(roomEnterMessageFormat, roomName);
|
|
|
|
roomEnterMessagePanel.SetActive(true);
|
|
|
|
if (roomEnterMessageCoroutine != null)
|
|
{
|
|
StopCoroutine(roomEnterMessageCoroutine);
|
|
}
|
|
|
|
roomEnterMessageCoroutine = StartCoroutine(HideRoomEnterMessageAfterDelay());
|
|
}
|
|
|
|
private void PlaceRoomEnterMessageInFrontOfCamera()
|
|
{
|
|
if (!placeMessageInFrontOfCamera)
|
|
return;
|
|
|
|
if (roomEnterMessageRoot == null)
|
|
return;
|
|
|
|
if (messageCameraTarget == null)
|
|
{
|
|
if (Camera.main != null)
|
|
{
|
|
messageCameraTarget = Camera.main.transform;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 카메라가 아래를 보고 있어도 메시지가 바닥으로 들어가지 않게
|
|
// 카메라 forward에서 Y값을 제거해서 수평 방향만 사용
|
|
Vector3 flatForward = messageCameraTarget.forward;
|
|
flatForward.y = 0f;
|
|
|
|
if (flatForward.sqrMagnitude < 0.001f)
|
|
{
|
|
flatForward = messageCameraTarget.parent != null
|
|
? messageCameraTarget.parent.forward
|
|
: Vector3.forward;
|
|
|
|
flatForward.y = 0f;
|
|
}
|
|
|
|
flatForward.Normalize();
|
|
|
|
Vector3 targetPosition =
|
|
messageCameraTarget.position +
|
|
flatForward * messageDistance +
|
|
Vector3.up * messageHeightOffset;
|
|
|
|
roomEnterMessageRoot.position = targetPosition;
|
|
|
|
Quaternion targetRotation = Quaternion.LookRotation(flatForward, Vector3.up);
|
|
|
|
if (flipMessageRotation)
|
|
{
|
|
targetRotation *= Quaternion.Euler(0f, 180f, 0f);
|
|
}
|
|
|
|
roomEnterMessageRoot.rotation = targetRotation;
|
|
}
|
|
|
|
private IEnumerator HideRoomEnterMessageAfterDelay()
|
|
{
|
|
yield return new WaitForSeconds(roomEnterMessageDuration);
|
|
|
|
if (roomEnterMessagePanel != null)
|
|
{
|
|
roomEnterMessagePanel.SetActive(false);
|
|
}
|
|
|
|
roomEnterMessageCoroutine = null;
|
|
}
|
|
} |