diff --git a/Assets/KSH/PlayerStats.cs b/Assets/KSH/PlayerStats.cs index f0e92911..760b6f9b 100644 --- a/Assets/KSH/PlayerStats.cs +++ b/Assets/KSH/PlayerStats.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; +using UnityEngine.SceneManagement; using Random = UnityEngine.Random; public class PlayerStats : MonoBehaviour @@ -74,12 +75,33 @@ public class PlayerStats : MonoBehaviour LoadMessagePanel(); CheckBubble(); + + SceneManager.sceneLoaded += OnSceneLoaded; // 씬 전환 이벤트 } - + #region 말풍선(Bubble) 관련 - + + private void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + // 새 씬에서 메시지 패널 다시 로드 + LoadMessagePanel(); + CheckBubble(); + } + + // OnDestroy에서 이벤트 구독 해제 + private void OnDestroy() + { + SceneManager.sceneLoaded -= OnSceneLoaded; + } + private void LoadMessagePanel() { + if (messagePanelInstance != null) // 기존 패널 파괴 + { + Destroy(messagePanelInstance); + messagePanelInstance = null; + } + GameObject messagePanelPrefab = Resources.Load("Prefabs/MessagePanel"); if (messagePanelPrefab != null) @@ -88,6 +110,7 @@ public class PlayerStats : MonoBehaviour messagePanelInstance = Instantiate(messagePanelPrefab, canvas.transform); speechBubbleFollower = messagePanelInstance.GetComponent(); + speechBubbleFollower.SetPlayerTransform(); if (speechBubbleFollower != null) { @@ -122,8 +145,12 @@ public class PlayerStats : MonoBehaviour public void HideBubble() { - if(!isActiveBubble) - speechBubbleFollower.HideMessage(); + speechBubbleFollower.HideMessage(); + } + + public void ShowAndHideBubble(string text) + { + speechBubbleFollower.ShowAndHide(text); } #endregion @@ -263,6 +290,8 @@ public class PlayerStats : MonoBehaviour return ( wakeUpTime + 24f ) - timeStat; // 다음 날 오전 8시까지 남은 시간 } } + + #region Modify Stats // 행동에 따른 내부 스탯 변경 메서드 public void ModifyTime(float time, ActionType actionType) @@ -323,4 +352,6 @@ public class PlayerStats : MonoBehaviour ReputationStat = _gameConstants.maxReputation; } } + + #endregion } diff --git a/Assets/KSH/SpeechBubbleFollower.cs b/Assets/KSH/SpeechBubbleFollower.cs index 2777add0..fc96edf8 100644 --- a/Assets/KSH/SpeechBubbleFollower.cs +++ b/Assets/KSH/SpeechBubbleFollower.cs @@ -1,3 +1,4 @@ +using System.Collections; using UnityEngine; using UnityEngine.UI; using TMPro; @@ -13,12 +14,18 @@ public class SpeechBubbleFollower : MonoBehaviour private RectTransform rectTransform; private CanvasGroup canvasGroup; + private float minDistance = 3f; + private float maxDistance = 8f; + private float minOffsetScale = 0.7f; + + private Coroutine hideCoroutine; // 자동 숨김용 코루틴 + // 랜덤 메시지 private string[] workReminderMessages = new string[] { "8시.. 출근하자.", "출근...해야 하나.", - "회사가 날 기다린다." + "회사가 기다린다." }; private void Awake() @@ -35,7 +42,11 @@ public class SpeechBubbleFollower : MonoBehaviour private void Start() { mainCamera = Camera.main; - + SetPlayerTransform(); + } + + public void SetPlayerTransform() + { if (playerTransform == null) { playerTransform = GameObject.FindGameObjectWithTag("Player").transform; @@ -46,15 +57,23 @@ public class SpeechBubbleFollower : MonoBehaviour { if (!gameObject.activeInHierarchy || playerTransform == null) return; - + + // Z축 거리 계산 + float zDistance = Mathf.Abs(mainCamera.transform.position.z - playerTransform.position.z); + + // 거리에 따른 오프셋 비율 계산 (멀어질수록 작아짐) + float normalizedDistance = Mathf.Clamp01((zDistance - minDistance) / (maxDistance - minDistance)); + float offsetScale = Mathf.Lerp(1f, minOffsetScale, normalizedDistance); + + // 실제 적용할 오프셋 계산 + Vector3 scaledOffset = offset * offsetScale; + // 플레이어 위치를 스크린 좌표로 변환 Vector3 screenPosition = mainCamera.WorldToScreenPoint(playerTransform.position); - - // 화면 상의 위치만 사용 (z값은 무시) screenPosition.z = 0; - - // 고정된 오프셋 적용 - rectTransform.position = screenPosition + offset; + + // 위치 적용 + transform.position = screenPosition + scaledOffset; } public void ShowMessage() // 랜덤 텍스트 표시 @@ -72,4 +91,30 @@ public class SpeechBubbleFollower : MonoBehaviour { gameObject.SetActive(false); } + + public void ShowAndHide(string text) + { + // 텍스트 설정 + if (bubbleText != null) + bubbleText.text = text; + + // 말풍선 활성화 + gameObject.SetActive(true); + canvasGroup.alpha = 1f; + + // 이전에 실행 중인 코루틴이 있다면 중지 + if (hideCoroutine != null) + StopCoroutine(hideCoroutine); + + // 3초 후 자동 숨김 코루틴 시작 + hideCoroutine = StartCoroutine(HideAfterDelay(3f)); + } + + // 일정 시간 후 말풍선을 숨기는 코루틴 + private IEnumerator HideAfterDelay(float delay) + { + yield return new WaitForSeconds(delay); + HideMessage(); + hideCoroutine = null; + } } \ No newline at end of file diff --git a/Assets/LIN/Scripts/DailyRoutine/InteractionController.cs b/Assets/LIN/Scripts/DailyRoutine/InteractionController.cs index be753f8e..3bddae99 100644 --- a/Assets/LIN/Scripts/DailyRoutine/InteractionController.cs +++ b/Assets/LIN/Scripts/DailyRoutine/InteractionController.cs @@ -23,6 +23,7 @@ public class InteractionController : MonoBehaviour // 상호작용 가능한 사물 범위에 들어올 때 private void OnTriggerEnter(Collider other) { + PlayerStats.Instance.HideBubble(); if(other.gameObject.layer == LayerMask.NameToLayer("NPC")) { housingCanvasController.ShowNpcInteractionButton(() => @@ -47,6 +48,7 @@ public class InteractionController : MonoBehaviour if (interactionLayerMask == (interactionLayerMask | (1 << other.gameObject.layer))) { + PlayerStats.Instance.ShowBubble(); housingCanvasController.HideInteractionButton(); housingCanvasController.interactionTextsController.InitInteractionTexts(); } @@ -65,17 +67,18 @@ public class InteractionController : MonoBehaviour { if (!PlayerStats.Instance.CanWork()) // 출근 가능한 시간이 아닐 경우 { - // 텍스트 출력 X ?? - Debug.Log("Can't work"); - housingCanvasController.interactionTextsController.ActiveTexts( "출근 가능한 시간이 아닙니다!"); + PlayerStats.Instance.ShowAndHideBubble("출근 시간이 아냐"); return; } } - PlayerStats.Instance.PerformAction(interactionType); - if (interactionType == ActionType.Dungeon) { + if (PlayerStats.Instance.CanWork()) // 출근 시간인데 던전에 가려하는 경우 + { + PlayerStats.Instance.ShowAndHideBubble("출근 시간해야 해"); + return; + } GameManager.Instance.ChangeToGameScene(); } else @@ -83,9 +86,12 @@ public class InteractionController : MonoBehaviour GameManager.Instance.PlayInteractionSound(interactionType); interactionAnimationPanelController.ShowAnimationPanel(interactionType,interactionTexts.AnimationText); } + + PlayerStats.Instance.PerformAction(interactionType); } else { + PlayerStats.Instance.ShowAndHideBubble("체력이 없어..."); housingCanvasController.interactionTextsController.ActiveTexts(interactionTexts.LackOfHealth); } }); diff --git a/Assets/LIN/Scripts/UI/InteractionAnimationPanelController.cs b/Assets/LIN/Scripts/UI/InteractionAnimationPanelController.cs index 228c23d1..77ebdc6a 100644 --- a/Assets/LIN/Scripts/UI/InteractionAnimationPanelController.cs +++ b/Assets/LIN/Scripts/UI/InteractionAnimationPanelController.cs @@ -25,6 +25,8 @@ public class InteractionAnimationPanelController : MonoBehaviour public void ShowAnimationPanel(ActionType actionType, string animationText) { + PlayerStats.Instance.HideBubble(); + // 1) 패널 활성화 panel.SetActive(true); // 2) 기존 코루틴 정리 @@ -110,6 +112,7 @@ public class InteractionAnimationPanelController : MonoBehaviour // 패널 닫히고 결근 체크, 상호작용 패널과 결근 엔딩 채팅창이 겹치지 않기 위함 PlayerStats.Instance.CheckAbsent(); + PlayerStats.Instance.ShowBubble(); } public void TutorialSleepAnimation() diff --git a/Assets/Resources/Dialogues/dialogue.json b/Assets/Resources/Dialogues/dialogue.json index ab8b7e91..38b6326c 100644 --- a/Assets/Resources/Dialogues/dialogue.json +++ b/Assets/Resources/Dialogues/dialogue.json @@ -185,7 +185,7 @@ { "id": "player_zero_3", "name": "주인공", - "text": "내가... 해고? 내가? \n 이럴.. 이럴리가 없어!!", + "text": "내가... 해고? 내가?", "nextId": "fairy_zero_4", "phase": "zero" },