diff --git a/.idea/.idea.Degulleo3DTutorials/.idea/.gitignore b/.idea/.idea.Degulleo3DTutorials/.idea/.gitignore
new file mode 100644
index 00000000..5904b5cd
--- /dev/null
+++ b/.idea/.idea.Degulleo3DTutorials/.idea/.gitignore
@@ -0,0 +1,13 @@
+# 디폴트 무시된 파일
+/shelf/
+/workspace.xml
+# Rider에서 무시된 파일
+/.idea.Degulleo3DTutorials.iml
+/projectSettingsUpdater.xml
+/contentModel.xml
+/modules.xml
+# 에디터 기반 HTTP 클라이언트 요청
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Degulleo3DTutorials/.idea/indexLayout.xml b/.idea/.idea.Degulleo3DTutorials/.idea/indexLayout.xml
new file mode 100644
index 00000000..7b08163c
--- /dev/null
+++ b/.idea/.idea.Degulleo3DTutorials/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Degulleo3DTutorials/.idea/vcs.xml b/.idea/.idea.Degulleo3DTutorials/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/.idea.Degulleo3DTutorials/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Assets/LIN/Housing Copy.unity b/Assets/LIN/Housing Copy.unity
index 0a1561fc..3dee420a 100644
--- a/Assets/LIN/Housing Copy.unity
+++ b/Assets/LIN/Housing Copy.unity
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0eefa4bbfa3ac0e963a5464f3dbe3292376003e14d61dad7a394b52508698028
-size 139931
+oid sha256:6a33904fb9e76c9041c648d161a9e7667157600ad6f987e1c500d3c388705824
+size 261255
diff --git a/Assets/LIN/Prefabs/JoystickPanel.prefab b/Assets/LIN/Prefabs/JoystickPanel.prefab
new file mode 100644
index 00000000..dc23f970
--- /dev/null
+++ b/Assets/LIN/Prefabs/JoystickPanel.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ad7c2d01633f79023bd478dc15868e75d4473d6b146bd15fa9e11e16d7b70878
+size 22447
diff --git a/Assets/LIN/Prefabs/JoystickPanel.prefab.meta b/Assets/LIN/Prefabs/JoystickPanel.prefab.meta
new file mode 100644
index 00000000..f2fdb7b4
--- /dev/null
+++ b/Assets/LIN/Prefabs/JoystickPanel.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ce82122427e6b6246b822185fdb82c2e
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Prefabs/Player.prefab b/Assets/LIN/Prefabs/Player.prefab
new file mode 100644
index 00000000..6aa84751
--- /dev/null
+++ b/Assets/LIN/Prefabs/Player.prefab
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0553b7a35d53197953565057a3417200ab8578e6a355275b67f63fb426c3f3c1
+size 78560
diff --git a/Assets/LIN/Prefabs/Player.prefab.meta b/Assets/LIN/Prefabs/Player.prefab.meta
new file mode 100644
index 00000000..cc58ec1a
--- /dev/null
+++ b/Assets/LIN/Prefabs/Player.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 0a190a5b9816abf478788174c2c55c62
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Test.meta b/Assets/LIN/Scripts/Test.meta
new file mode 100644
index 00000000..c1bb3539
--- /dev/null
+++ b/Assets/LIN/Scripts/Test.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 18265c81aaa1344439d5501a08b7a633
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Test/FirstTutorialStep.asset b/Assets/LIN/Scripts/Test/FirstTutorialStep.asset
new file mode 100644
index 00000000..fb2b0c6a
--- /dev/null
+++ b/Assets/LIN/Scripts/Test/FirstTutorialStep.asset
@@ -0,0 +1,25 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b22d834cf5e26e647be215074940d40e, type: 3}
+ m_Name: FirstTutorialStep
+ m_EditorClassIdentifier:
+ message: Let's begin tutorial. First, touch next button.
+ onBegin:
+ m_PersistentCalls:
+ m_Calls: []
+ onComplete:
+ m_PersistentCalls:
+ m_Calls: []
+ timeout: 0
+ requiredKey: 0
+ touchTargetIndex: 0
+ nextStep: {fileID: 11400000, guid: 83b9fc17fee6d884fb0c4ea5fc25e175, type: 2}
diff --git a/Assets/LIN/Scripts/Test/FirstTutorialStep.asset.meta b/Assets/LIN/Scripts/Test/FirstTutorialStep.asset.meta
new file mode 100644
index 00000000..91747534
--- /dev/null
+++ b/Assets/LIN/Scripts/Test/FirstTutorialStep.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a7cedb06e57fff540a2335f42ac38e2c
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Test/SecondTutorialStep.asset b/Assets/LIN/Scripts/Test/SecondTutorialStep.asset
new file mode 100644
index 00000000..aabf1699
--- /dev/null
+++ b/Assets/LIN/Scripts/Test/SecondTutorialStep.asset
@@ -0,0 +1,25 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b22d834cf5e26e647be215074940d40e, type: 3}
+ m_Name: SecondTutorialStep
+ m_EditorClassIdentifier:
+ message: Well done, now then touch the button which has round shape
+ onBegin:
+ m_PersistentCalls:
+ m_Calls: []
+ onComplete:
+ m_PersistentCalls:
+ m_Calls: []
+ timeout: 0
+ requiredKey: 0
+ touchTargetIndex: 1
+ nextStep: {fileID: 0}
diff --git a/Assets/LIN/Scripts/Test/SecondTutorialStep.asset.meta b/Assets/LIN/Scripts/Test/SecondTutorialStep.asset.meta
new file mode 100644
index 00000000..c2b6cfb4
--- /dev/null
+++ b/Assets/LIN/Scripts/Test/SecondTutorialStep.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 83b9fc17fee6d884fb0c4ea5fc25e175
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Tutorial.meta b/Assets/LIN/Scripts/Tutorial.meta
new file mode 100644
index 00000000..9daf2ed4
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4153e2ad34614334a86d1fc810eaed5e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Tutorial/FirstTutorialStep.asset b/Assets/LIN/Scripts/Tutorial/FirstTutorialStep.asset
new file mode 100644
index 00000000..db05f32d
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial/FirstTutorialStep.asset
@@ -0,0 +1,25 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b22d834cf5e26e647be215074940d40e, type: 3}
+ m_Name: FirstTutorialStep
+ m_EditorClassIdentifier:
+ message:
+ onBegin:
+ m_PersistentCalls:
+ m_Calls: []
+ onComplete:
+ m_PersistentCalls:
+ m_Calls: []
+ timeout: 0
+ requiredKey: 0
+ touchTargetIndex: 0
+ nextStep: {fileID: 0}
diff --git a/Assets/LIN/Scripts/Tutorial/FirstTutorialStep.asset.meta b/Assets/LIN/Scripts/Tutorial/FirstTutorialStep.asset.meta
new file mode 100644
index 00000000..62470ab2
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial/FirstTutorialStep.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 80e7d98a23eacbb4eab74b9a479a04e2
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Tutorial/TutorialManager.cs b/Assets/LIN/Scripts/Tutorial/TutorialManager.cs
new file mode 100644
index 00000000..0d6f2897
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial/TutorialManager.cs
@@ -0,0 +1,112 @@
+using System;
+using UnityEngine;
+using TMPro;
+using UnityEngine.UI;
+using System.Collections;
+
+public class TutorialManager : MonoBehaviour
+{
+ [SerializeField] private TutorialStep firstStep;
+ [SerializeField] private CanvasGroup overlay; // 입력 차단 & 다크닝용
+ [SerializeField] private TMP_Text tutorialText;
+ [SerializeField] private Canvas overlayCanvas; // RectTransformUtility를 위한 Canvas
+ // [SerializeField] private GameObject housingUICanvas; //튜토리얼 동안 입력 제한
+
+ [Header("튜토리얼 터치 타겟들")]
+ [SerializeField] private GameObject[] touchTargets;
+
+ [Header("터치 타겟에 맞춰 감춰놓을 게임 오브젝트")]
+ [SerializeField] private GameObject[] lockTargets;
+
+ private Coroutine _runningCoroutine;
+ private RectTransform targetRt;
+
+ public void Start()
+ {
+ StartTutorial();
+ }
+
+ public void StartTutorial()
+ {
+ overlay.alpha = 1f;
+ overlay.blocksRaycasts = true;
+ RunStep(firstStep);
+ }
+
+ private void RunStep(TutorialStep step)
+ {
+ if (_runningCoroutine != null) StopCoroutine(_runningCoroutine);
+ _runningCoroutine = StartCoroutine(RunStepCoroutine(step));
+ }
+
+ private IEnumerator RunStepCoroutine(TutorialStep step)
+ {
+ // 단계 시작 이벤트
+ step.onBegin?.Invoke();
+ // 메시지 갱신
+ tutorialText.text = step.message;
+
+ float elapsed = 0f;
+ bool done = false;
+
+ //터치해야 할 위치가 있는지 체크
+ if (step.touchTargetIndex >= 0)
+ {
+ targetRt = touchTargets[step.touchTargetIndex].GetComponent();
+ lockTargets[step.touchTargetIndex].SetActive(false);
+ }
+
+ while (!done)
+ {
+ // 1) 영역 터치 체크
+ if (targetRt != null)
+ {
+ // 클릭 또는 터치 이벤트
+ bool pressed = Input.GetMouseButtonDown(0) || Input.touchCount > 0;
+ if (pressed)
+ {
+ Vector2 screenPos = Input.touchCount > 0
+ ? Input.GetTouch(0).position
+ : (Vector2)Input.mousePosition;
+
+ // 터치 위치가 지정 RectTransform 안에 있는지 검사
+ if (RectTransformUtility.RectangleContainsScreenPoint(
+ targetRt, screenPos, overlayCanvas.worldCamera))
+ {
+ yield return new WaitForSeconds(1f);
+ // done = true;
+ // Debug.Log("영역 터치");
+ }
+ }
+ }
+
+ // 타임아웃 체크
+ if (step.timeout > 0f && elapsed >= step.timeout)
+ done = true;
+
+ // 키 입력 체크
+ if (step.requiredKey != KeyCode.None && Input.GetKeyDown(step.requiredKey))
+ done = true;
+
+
+ elapsed += Time.deltaTime;
+ yield return null;
+ }
+
+ // 단계 완료 이벤트
+ step.onComplete?.Invoke();
+
+ // 다음 단계로
+ if (step.nextStep != null)
+ RunStep(step.nextStep);
+ else
+ EndTutorial();
+ }
+
+ private void EndTutorial()
+ {
+ tutorialText.text = "";
+ overlay.alpha = 0f;
+ overlay.blocksRaycasts = false;
+ }
+}
\ No newline at end of file
diff --git a/Assets/LIN/Scripts/Tutorial/TutorialManager.cs.meta b/Assets/LIN/Scripts/Tutorial/TutorialManager.cs.meta
new file mode 100644
index 00000000..36be15fc
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial/TutorialManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 93a1ace26bb85054ba68cb96470bd8c6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Scripts/Tutorial/TutorialStep.cs b/Assets/LIN/Scripts/Tutorial/TutorialStep.cs
new file mode 100644
index 00000000..c94abc63
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial/TutorialStep.cs
@@ -0,0 +1,21 @@
+using UnityEngine;
+using UnityEngine.Events;
+
+[CreateAssetMenu(fileName = "TutorialStep", menuName = "Tutorial/Tutorial Step")]
+public class TutorialStep : ScriptableObject
+{
+ [TextArea(2, 5)]
+ public string message; // 플레이어에게 보여줄 텍스트
+
+ public UnityEvent onBegin; // 단계 시작 시 추가로 실행할 이벤트
+ public UnityEvent onComplete; // 단계 완료 시 실행할 이벤트
+
+ public float timeout = 0f; // 0 이상이면 이 시간 경과 후 자동 완료
+ public KeyCode requiredKey = KeyCode.None; // 지정 Key 입력 시 완료
+
+ [Tooltip("터치해야 할 위치가 있다면, 게임매니저에게 인덱스 전달")]
+ public int touchTargetIndex=-1;
+
+ [Tooltip("다음 단계로 넘어갈 TutorialStep, null이면 튜토리얼 종료")]
+ public TutorialStep nextStep;
+}
\ No newline at end of file
diff --git a/Assets/LIN/Scripts/Tutorial/TutorialStep.cs.meta b/Assets/LIN/Scripts/Tutorial/TutorialStep.cs.meta
new file mode 100644
index 00000000..72728424
--- /dev/null
+++ b/Assets/LIN/Scripts/Tutorial/TutorialStep.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b22d834cf5e26e647be215074940d40e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/LIN/Tutorial Test.unity b/Assets/LIN/Tutorial Test.unity
new file mode 100644
index 00000000..b2c4d6bc
--- /dev/null
+++ b/Assets/LIN/Tutorial Test.unity
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1f62055cb48413ada6c5bd338d2eb496316e1d088891d121db05436c8c74cdd8
+size 30756
diff --git a/Assets/LIN/Tutorial Test.unity.meta b/Assets/LIN/Tutorial Test.unity.meta
new file mode 100644
index 00000000..9830d118
--- /dev/null
+++ b/Assets/LIN/Tutorial Test.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: da4de4222cef76849866bab5f0adcaaa
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant: