diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 00000000..f019fd0a --- /dev/null +++ b/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/Assets/01_Scenes/test.meta b/Assets/01_Scenes/test.meta new file mode 100644 index 00000000..e89670f2 --- /dev/null +++ b/Assets/01_Scenes/test.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c8e12991b4e9da4cae8a152c52eadba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/test/1.unity b/Assets/01_Scenes/test/1.unity new file mode 100644 index 00000000..8b11eea4 --- /dev/null +++ b/Assets/01_Scenes/test/1.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:74f09ae142e8dc56f5bd62755719c2ebe3222e5e23f3086ae102b8cfdaaf0c75 +size 15102 diff --git a/Assets/01_Scenes/test/1.unity.meta b/Assets/01_Scenes/test/1.unity.meta new file mode 100644 index 00000000..93026f83 --- /dev/null +++ b/Assets/01_Scenes/test/1.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 35897533394ad724cab0afd3b3bea74b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/test/2.unity b/Assets/01_Scenes/test/2.unity new file mode 100644 index 00000000..389ad72c --- /dev/null +++ b/Assets/01_Scenes/test/2.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e4aa94d6409a16b2e25f268399fc6e604fc3cb60681c86328337b2a09d1f7e9 +size 11349 diff --git a/Assets/01_Scenes/test/2.unity.meta b/Assets/01_Scenes/test/2.unity.meta new file mode 100644 index 00000000..baca3eb4 --- /dev/null +++ b/Assets/01_Scenes/test/2.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 70194d04fb069be4b84ec6f17a5041cc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/test/3.unity b/Assets/01_Scenes/test/3.unity new file mode 100644 index 00000000..feb02199 --- /dev/null +++ b/Assets/01_Scenes/test/3.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f60e17e2763b9ea264dda40d6a8e00754d1d723276c6f9a06ce131c7391d7b68 +size 11325 diff --git a/Assets/01_Scenes/test/3.unity.meta b/Assets/01_Scenes/test/3.unity.meta new file mode 100644 index 00000000..f7e6ba2b --- /dev/null +++ b/Assets/01_Scenes/test/3.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 44d13b2a5a7bee0409f1a5c7d0486e35 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/test/4.unity b/Assets/01_Scenes/test/4.unity new file mode 100644 index 00000000..68009137 --- /dev/null +++ b/Assets/01_Scenes/test/4.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31cdb0cb4ae220ad4fec9d7c96c032decfda5d974ce428171c6ef32279e2e4e6 +size 21428 diff --git a/Assets/01_Scenes/test/4.unity.meta b/Assets/01_Scenes/test/4.unity.meta new file mode 100644 index 00000000..00f9fcb5 --- /dev/null +++ b/Assets/01_Scenes/test/4.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fda7347beb006a24fafc02220fe9d5f5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01_Scenes/test/test.unity b/Assets/01_Scenes/test/test.unity new file mode 100644 index 00000000..44c4482e --- /dev/null +++ b/Assets/01_Scenes/test/test.unity @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9cfeec8f34f9f3a79f7ecadc4d90a42819a3c4b893d66be3f92263fa0071f9a +size 11386 diff --git a/Assets/01_Scenes/test/test.unity.meta b/Assets/01_Scenes/test/test.unity.meta new file mode 100644 index 00000000..780016f3 --- /dev/null +++ b/Assets/01_Scenes/test/test.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9cb5c840e1b895a4d81a65fe59250140 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/02_Scripts/Managers/RoomMoveButton.cs b/Assets/02_Scripts/Managers/RoomMoveButton.cs new file mode 100644 index 00000000..74864f1e --- /dev/null +++ b/Assets/02_Scripts/Managers/RoomMoveButton.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +public class RoomMoveButton : MonoBehaviour +{ + [Header(" ư ̵ ȣ Է")] + [SerializeField] private int targetRoomNumber; + + public void OnClickMoveRoom() + { + if (RoomRouteManager.Instance == null) + { + Debug.LogError("RoomRouteManager ϴ."); + return; + } + + RoomRouteManager.Instance.MoveToRoom(targetRoomNumber); + } +} \ No newline at end of file diff --git a/Assets/02_Scripts/Managers/RoomMoveButton.cs.meta b/Assets/02_Scripts/Managers/RoomMoveButton.cs.meta new file mode 100644 index 00000000..efeacb5b --- /dev/null +++ b/Assets/02_Scripts/Managers/RoomMoveButton.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8eb4311a25437fd468487f681f4662e3 \ No newline at end of file diff --git a/Assets/02_Scripts/Managers/RoomRouteDebugTester.cs b/Assets/02_Scripts/Managers/RoomRouteDebugTester.cs new file mode 100644 index 00000000..6b1b63c3 --- /dev/null +++ b/Assets/02_Scripts/Managers/RoomRouteDebugTester.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.InputSystem; + +public class RoomRouteDebugTester : MonoBehaviour +{ + private List currentChoices = + new List(); + + private void Update() + { + if (RoomRouteManager.Instance == null) + { + return; + } + + if (Keyboard.current == null) + { + return; + } + + // CŰ: 湮 ĺ ̱ + if (Keyboard.current.cKey.wasPressedThisFrame) + { + currentChoices = RoomRouteManager.Instance.GetRandomNextRooms(); + + Debug.Log($" ĺ : {currentChoices.Count}"); + + for (int i = 0; i < currentChoices.Count; i++) + { + Debug.Log($"{i + 1} ȣ: {currentChoices[i].roomNumber}, ̸: {currentChoices[i].sceneName}"); + } + } + + // 1Ű: ù ° ĺ + if (Keyboard.current.digit1Key.wasPressedThisFrame) + { + MoveToChoice(0); + } + + // 2Ű: ° ĺ + if (Keyboard.current.digit2Key.wasPressedThisFrame) + { + MoveToChoice(1); + } + + // TŰ: 湮 Ȯ + if (Keyboard.current.tKey.wasPressedThisFrame) + { + Debug.Log($"湮 : {RoomRouteManager.Instance.VisitedRoomCount} / {RoomRouteManager.Instance.TotalRoomCount}"); + Debug.Log($" ȣ: {RoomRouteManager.Instance.CurrentRoomNumber}"); + } + + // XŰ: ׽Ʈ 湮 ʱȭ + if (Keyboard.current.xKey.wasPressedThisFrame) + { + Debug.Log("湮 ʱȭ"); + currentChoices.Clear(); + RoomRouteManager.Instance.ResetVisitedRooms(); + } + + // FŰ: 湮 ̵ ׽Ʈ + if (Keyboard.current.fKey.wasPressedThisFrame) + { + Debug.Log(" ̵ ׽Ʈ"); + RoomRouteManager.Instance.MoveToFinalScene(); + } + } + + private void MoveToChoice(int index) + { + if (currentChoices == null || currentChoices.Count == 0) + { + Debug.LogWarning(" CŰ ĺ ̾ƾ մϴ."); + return; + } + + if (index < 0 || index >= currentChoices.Count) + { + Debug.LogWarning("ش ȣ ϴ."); + return; + } + + int targetRoomNumber = currentChoices[index].roomNumber; + + Debug.Log($"{index + 1} {targetRoomNumber} ̵"); + + currentChoices.Clear(); + + RoomRouteManager.Instance.MoveToRoom(targetRoomNumber); + } +} \ No newline at end of file diff --git a/Assets/02_Scripts/Managers/RoomRouteDebugTester.cs.meta b/Assets/02_Scripts/Managers/RoomRouteDebugTester.cs.meta new file mode 100644 index 00000000..b225af43 --- /dev/null +++ b/Assets/02_Scripts/Managers/RoomRouteDebugTester.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9e414802b02a03e469c541b086f805bb \ No newline at end of file diff --git a/Assets/02_Scripts/Managers/RoomRouteManager.cs b/Assets/02_Scripts/Managers/RoomRouteManager.cs new file mode 100644 index 00000000..308e631d --- /dev/null +++ b/Assets/02_Scripts/Managers/RoomRouteManager.cs @@ -0,0 +1,219 @@ +using System.Collections.Generic; +using UnityEngine; + +public class RoomRouteManager : MonoBehaviour +{ + public static RoomRouteManager Instance; + + [System.Serializable] + public class RoomData + { + [Header(" ȣ Է")] + public int roomNumber; + + [Header(" 濡 شϴ Scene ̸ Է")] + public string sceneName; + } + + [Header("ü Է")] + [SerializeField] private List rooms = new List(); + + [Header(" ȣ Է")] + [SerializeField] private int startRoomNumber; + + [Header(" ")] + [SerializeField] private int randomChoiceCount = 2; + + [Header(" 湮 ̵ Scene ̸")] + [SerializeField] private string finalSceneName; + + private int _currentRoomNumber; + private readonly HashSet _visitedRooms = new HashSet(); + + public int CurrentRoomNumber => _currentRoomNumber; + public int VisitedRoomCount => _visitedRooms.Count; + public int TotalRoomCount => rooms.Count; + + private void Awake() + { + if (Instance == null) + { + Instance = this; + DontDestroyOnLoad(gameObject); + + _currentRoomNumber = startRoomNumber; + + if (startRoomNumber != 0) + { + _visitedRooms.Add(startRoomNumber); + } + } + else + { + Destroy(gameObject); + } + } + + // 湮 ü ȯ + public List GetUnvisitedRooms() + { + List result = new List(); + + foreach (RoomData room in rooms) + { + if (!_visitedRooms.Contains(room.roomNumber)) + { + result.Add(room); + } + } + + return result; + } + + // ȭ ȯ + public List GetRandomNextRooms() + { + List unvisitedRooms = GetUnvisitedRooms(); + List randomRooms = new List(); + + int count = Mathf.Min(randomChoiceCount, unvisitedRooms.Count); + + for (int i = 0; i < count; i++) + { + int randomIndex = Random.Range(0, unvisitedRooms.Count); + + randomRooms.Add(unvisitedRooms[randomIndex]); + unvisitedRooms.RemoveAt(randomIndex); + } + + return randomRooms; + } + + // ư̳ ȭ ȣ + public void MoveToRoom(int roomNumber) + { + if (SceneLoadManager.Instance == null) + { + Debug.LogError("SceneLoadManager ϴ."); + return; + } + + if (SceneLoadManager.Instance.IsChangingScene) + { + Debug.Log("̹ ̵ Դϴ."); + return; + } + + RoomData targetRoom = GetRoomData(roomNumber); + + if (targetRoom == null) + { + Debug.LogWarning($" ã ϴ. ȣ: {roomNumber}"); + return; + } + + if (_visitedRooms.Contains(roomNumber)) + { + Debug.Log($"̹ 湮 Դϴ. ȣ: {roomNumber}"); + return; + } + + if (string.IsNullOrEmpty(targetRoom.sceneName)) + { + Debug.LogWarning($" {roomNumber} Scene ̸ ֽϴ."); + return; + } + + _currentRoomNumber = roomNumber; + _visitedRooms.Add(roomNumber); + + SceneLoadManager.Instance.RequestSceneChange(targetRoom.sceneName); + } + + // ϳ ٷ ̵ϰ + public void MoveToRandomRoom() + { + List unvisitedRooms = GetUnvisitedRooms(); + + if (unvisitedRooms.Count <= 0) + { + Debug.Log("湮 ϴ."); + + if (IsAllRoomsVisited()) + { + MoveToFinalScene(); + } + + return; + } + + int randomIndex = Random.Range(0, unvisitedRooms.Count); + RoomData randomRoom = unvisitedRooms[randomIndex]; + + MoveToRoom(randomRoom.roomNumber); + } + + public bool IsAllRoomsVisited() + { + return rooms.Count > 0 && _visitedRooms.Count >= rooms.Count; + } + + public void MoveToFinalScene() + { + if (!IsAllRoomsVisited()) + { + Debug.Log(" 湮 ʾҽϴ."); + return; + } + + if (SceneLoadManager.Instance == null) + { + Debug.LogError("SceneLoadManager ϴ."); + return; + } + + if (SceneLoadManager.Instance.IsChangingScene) + { + Debug.Log("̹ ̵ Դϴ."); + return; + } + + if (string.IsNullOrEmpty(finalSceneName)) + { + Debug.LogWarning(" Scene ̸ ֽϴ."); + return; + } + + SceneLoadManager.Instance.RequestSceneChange(finalSceneName); + } + + public bool IsVisitedRoom(int roomNumber) + { + return _visitedRooms.Contains(roomNumber); + } + + public void ResetVisitedRooms() + { + _visitedRooms.Clear(); + + _currentRoomNumber = startRoomNumber; + + if (startRoomNumber != 0) + { + _visitedRooms.Add(startRoomNumber); + } + } + + private RoomData GetRoomData(int roomNumber) + { + foreach (RoomData room in rooms) + { + if (room.roomNumber == roomNumber) + { + return room; + } + } + + return null; + } +} \ No newline at end of file diff --git a/Assets/02_Scripts/Managers/RoomRouteManager.cs.meta b/Assets/02_Scripts/Managers/RoomRouteManager.cs.meta new file mode 100644 index 00000000..5fb2a0d7 --- /dev/null +++ b/Assets/02_Scripts/Managers/RoomRouteManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0a9c2a7a081e65e43806d1ecb3cca28c \ No newline at end of file diff --git a/Assets/02_Scripts/Managers/SceneLoadManager.cs b/Assets/02_Scripts/Managers/SceneLoadManager.cs index 055c7dba..2ace62b8 100644 --- a/Assets/02_Scripts/Managers/SceneLoadManager.cs +++ b/Assets/02_Scripts/Managers/SceneLoadManager.cs @@ -1,6 +1,7 @@ using System; using UnityEngine; using UnityEngine.SceneManagement; + public class SceneLoadManager : MonoBehaviour { public static SceneLoadManager Instance; @@ -9,16 +10,20 @@ public class SceneLoadManager : MonoBehaviour [SerializeField] private Camera _loadingCam; [SerializeField] private Transform _loadingCamTargetTransform; + private bool _isChangingScene = false; + + public bool IsChangingScene => _isChangingScene; + private void Awake() { if (Instance == null) { - Instance = this; //만들어진 자신을 인스턴스로 설정 + Instance = this; // 만들어진 자신을 인스턴스로 설정 DontDestroyOnLoad(gameObject); } else { - Destroy(gameObject); //이미 인스턴스가 있으면 자신을 파괴 + Destroy(gameObject); // 이미 인스턴스가 있으면 자신을 파괴 } } @@ -28,15 +33,23 @@ private void Start() OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single); } + private void OnDestroy() + { + if (Instance == this) + { + SceneManager.sceneLoaded -= OnSceneLoaded; + } + } + private void Update() { - if(_loadingCamTargetTransform != null) + if (_loadingRoot != null && _loadingCamTargetTransform != null) { _loadingRoot.transform.position = _loadingCamTargetTransform.position; } } - //씬이 로드되었을때 호출 + // 씬이 로드되었을때 호출 private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { MonoBehaviour[] allObjs = UnityEngine.Object.FindObjectsByType(FindObjectsSortMode.None); @@ -45,7 +58,7 @@ private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (obj is ISceneInitializable initializable) { - //씬에서 ISceneInitializable 인터페이스를 가진 오브젝트의 초기화 로직을 실행 + // 씬에서 ISceneInitializable 인터페이스를 가진 오브젝트의 초기화 로직을 실행 initializable.OnSceneLoaded(); } } @@ -53,11 +66,23 @@ private void OnSceneLoaded(Scene scene, LoadSceneMode mode) public void SetSceneLoadingProgressValue(float value) { - + // 여기에 로딩바 UI 연결 예정 } public void RequestSceneChange(string sceneName) { + if (_isChangingScene) + { + Debug.Log("이미 씬 전환 중입니다."); + return; + } + + if (string.IsNullOrEmpty(sceneName)) + { + Debug.LogWarning("이동할 씬 이름이 비어있습니다."); + return; + } + _ = SceneChange(sceneName); } @@ -65,35 +90,49 @@ private async Awaitable SceneChange(string sceneName) { try { - //로딩바 수치 0으로 설정 + _isChangingScene = true; + + // 로딩바 수치 0으로 설정 SetSceneLoadingProgressValue(0f); + if (_loadingRoot != null) + { + _loadingRoot.SetActive(true); + } + AsyncOperation op = SceneManager.LoadSceneAsync(sceneName); - //자동 전환을 하고 싶지 않을 경우 해당값을 false로 두었다가 true로 바꾸면 그 때 전환됨 + if (op == null) + { + Debug.LogError($"씬 로드 실패: {sceneName}"); + _isChangingScene = false; + return; + } + + // 자동 전환을 하고 싶지 않을 경우 false로 두었다가 true로 바꾸면 그 때 전환됨 op.allowSceneActivation = false; - //화면에 보여줄 로딩 수치 + // 화면에 보여줄 로딩 수치 float displayProgress = 0f; - //op.progress 0.9가 데이터 로딩이 끝난 기준 allowSceneActivation이 트루면 다음으로 넘어가면서 op.isDone이 true가 된다. - while (op.progress < 0.9f) + // op.progress 0.9가 데이터 로딩이 끝난 기준 + while (op.progress < 0.9f) { - //실제 로딩 수치 + // 실제 로딩 수치 float realProgress = Mathf.Clamp01(op.progress / 0.9f); - //보여줄 값을 실제값을 향해 부드럽게 이동 + // 보여줄 값을 실제값을 향해 부드럽게 이동 displayProgress = Mathf.MoveTowards(displayProgress, realProgress, Time.deltaTime * 0.5f); // 로딩바 UI에 값 적용 SetSceneLoadingProgressValue(displayProgress); - //자기자신이 파괴될때 토큰에 취소요청을 보냄 + // 자기자신이 파괴될때 토큰에 취소요청을 보냄 await Awaitable.NextFrameAsync(this.destroyCancellationToken); } - //로딩바 수치 1(100%)로 설정 (데이터 로딩은 이미 끝이기 때문에) - SetSceneLoadingProgressValue(1); + // 로딩바 수치 1(100%)로 설정 + SetSceneLoadingProgressValue(1f); // 잠시 대기했다가 전환 await Awaitable.WaitForSecondsAsync(1.0f, this.destroyCancellationToken); @@ -102,19 +141,29 @@ private async Awaitable SceneChange(string sceneName) op.allowSceneActivation = true; // 씬 활성화가 완전히 끝날 때까지 대기 - // allowSceneActivation가 true가 되고 완전히 전환되기까지는 몇프레임 걸림. op.isDone 은 이 과정이 끝난 뒤에 true가 됨. - while(!op.isDone) + while (!op.isDone) { await Awaitable.NextFrameAsync(this.destroyCancellationToken); } - //VR용 로직 - //트래킹이 중단되면 안되기 때문에 카메라를 유지해야 한다 - _loadingCamTargetTransform = Camera.main.transform; // 새로운 씬의 메인카메라를 따라가게끔 설정 + // VR용 로직 + // 트래킹이 중단되면 안되기 때문에 카메라를 유지해야 한다 + if (Camera.main != null) + { + _loadingCamTargetTransform = Camera.main.transform; + } + + if (_loadingRoot != null) + { + _loadingRoot.SetActive(false); + } + + _isChangingScene = false; } catch (OperationCanceledException) { Debug.Log("씬 전환 작업이 취소됨"); + _isChangingScene = false; } } } \ No newline at end of file diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index c8e88b34..877358fb 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5adc987c1ef8f9f019bebc7114317f821c1c7d54c4e4ca88cd9505309309993d -size 1156 +oid sha256:79980c566d6789829ec652b5271dc43bbcbfafb2b4d0bd5fbbbfe0935fcc2efd +size 1546