피싱룸

This commit is contained in:
2026-06-26 18:05:00 +09:00
parent 35b22836fe
commit 45bc52b782
30 changed files with 3266 additions and 657 deletions

View File

@@ -12,6 +12,12 @@ public enum ResultType
Miss
}
public enum FishingControlMode
{
TimingGauge,
SimpleReel
}
[Header("Auto Bind")]
[Tooltip("현재 만든 Prefab 구조 기준으로 비어 있는 참조를 자동 연결합니다.")]
[SerializeField] private bool autoBindMissingReferences = true;
@@ -25,6 +31,28 @@ public enum ResultType
[SerializeField] private FishingHapticManager haptic;
[SerializeField] private RotateUI centerIconRotate;
[Header("Simple Reel Fishing")]
[Tooltip("TimingGauge는 기존 원형 타이밍 게이지 방식, SimpleReel은 릴을 감아 줄 길이를 줄이면 성공하는 방식입니다.")]
[SerializeField] private FishingControlMode fishingControlMode = FishingControlMode.SimpleReel;
[Tooltip("낚싯대 / 찌 / 릴 제어 스크립트입니다. SimpleReel 모드에서 줄 길이를 읽습니다.")]
[SerializeField] private FishingRodVRController rodController;
[Tooltip("현재 줄 길이가 이 값 이하가 되면 낚기 성공으로 처리합니다.")]
[SerializeField] private float catchCompleteLineLength = 0.7f;
[Tooltip("릴 낚시 시작 시 줄 길이가 성공 길이보다 너무 짧으면 이 거리만큼 최소 시작 길이를 보정합니다.")]
[SerializeField] private float simpleReelMinimumPullDistance = 0.35f;
[Tooltip("릴 낚기 성공 후 찌를 낚싯대 쪽 대기 위치로 회수합니다.")]
[SerializeField] private bool returnBobberAfterSimpleReelCatch = true;
[Tooltip("SimpleReel 모드에서 기존 타이밍 게이지 UI를 숨기고 진행도/줄 길이 중심으로 표시합니다.")]
[SerializeField] private bool hideTimingGaugeInSimpleReelMode = true;
[Tooltip("SimpleReel 모드에서는 StartFishing이 여러 번 호출됩니다. 켜면 첫 시작 때만 연못 상태를 초기화합니다.")]
[SerializeField] private bool resetPondOnlyOnFirstSimpleReelStart = true;
[Header("XR Controller Input")]
[Tooltip("낚시 판정을 실행할 컨트롤러 입력입니다. 예: XRI Right Interaction / Select")]
[SerializeField] private InputActionReference submitAction;
@@ -65,6 +93,9 @@ public enum ResultType
[Tooltip("StartFishing을 호출할 때 쓰레기 수거/연못 상태를 초기화합니다.")]
[SerializeField] private bool resetPondStateOnStart = true;
[Tooltip("낚시 세션이 진행 중일 때 StartFishing이 중복 호출되는 것을 막습니다.")]
[SerializeField] private bool preventRestartWhileSessionRunning = true;
[Header("Round Settings")]
[SerializeField] private float nextRoundDelay = 0.35f;
[SerializeField] private float nextCatchDelay = 2.0f;
@@ -95,9 +126,15 @@ public enum ResultType
private bool clockwise = true;
private bool activeGame;
private bool inputLocked;
private bool fishingSessionRunning;
private bool pondCleaned;
private bool memoryPieceCollected;
private bool simpleReelCatchActive;
private bool simpleReelPondInitialized;
private float simpleReelStartLineLength;
private float simpleReelProgress;
private bool submitActionWasEnabled;
private bool resetActionWasEnabled;
@@ -106,6 +143,7 @@ public enum ResultType
private Coroutine finalResultRoutine;
public bool IsActiveGame => activeGame;
public bool IsFishingSessionRunning => fishingSessionRunning;
public bool IsPondCleaned => pondCleaned;
public bool IsMemoryPieceCollected => memoryPieceCollected;
public int SuccessCount => successCount;
@@ -117,6 +155,9 @@ public enum ResultType
public int SessionTrashCount => sessionTrashCount;
public int SessionMemoryPieceCount => sessionMemoryPieceCount;
public int SessionCompassCount => sessionCompassCount;
public FishingControlMode ControlMode => fishingControlMode;
public bool IsSimpleReelCatchActive => simpleReelCatchActive;
public float SimpleReelProgress => simpleReelProgress;
public event Action<FishingItemType, int> ItemCaught;
@@ -154,6 +195,12 @@ private void Update()
if (!activeGame)
return;
if (fishingControlMode == FishingControlMode.SimpleReel)
{
UpdateSimpleReelCatch();
return;
}
if (inputLocked)
return;
@@ -188,6 +235,9 @@ public void AutoBindMissingReferences()
if (haptic == null)
haptic = searchRoot != null ? searchRoot.GetComponentInChildren<FishingHapticManager>(true) : GetComponentInChildren<FishingHapticManager>(true);
if (rodController == null)
rodController = searchRoot != null ? searchRoot.GetComponentInChildren<FishingRodVRController>(true) : GetComponentInChildren<FishingRodVRController>(true);
if (centerIconRotate == null)
{
Transform centerIconTransform = FindTransformRecursive(searchRoot, "CenterIcon");
@@ -276,6 +326,8 @@ private void ValidateRuntimeSettings()
nextRoundDelay = Mathf.Max(0f, nextRoundDelay);
nextCatchDelay = Mathf.Max(0f, nextCatchDelay);
finalResultShowTime = Mathf.Max(0f, finalResultShowTime);
catchCompleteLineLength = Mathf.Max(0.05f, catchCompleteLineLength);
simpleReelMinimumPullDistance = Mathf.Max(0.01f, simpleReelMinimumPullDistance);
pointerAngle = Normalize(pointerAngle);
zoneCenter = Normalize(zoneCenter);
@@ -293,6 +345,8 @@ private void InitializeIdleUI()
ui.UpdateInventoryUI(sessionFishCount, sessionTrashCount, sessionMemoryPieceCount, sessionCompassCount);
ui.SetPointerRotation(0f);
ui.SetZone(0f, startZoneSize);
ui.SetSimpleReelUIVisible(false);
ui.SetTimingGaugeVisible(fishingControlMode == FishingControlMode.TimingGauge);
}
if (centerIconRotate != null)
@@ -300,23 +354,50 @@ private void InitializeIdleUI()
}
public void StartFishing()
{
StartFishing(false);
}
public void StartFishing(bool forceRestart)
{
ValidateRuntimeSettings();
if (preventRestartWhileSessionRunning && fishingSessionRunning && !forceRestart)
{
if (showDebugLog)
Debug.Log("낚시 세션이 이미 진행 중이라 StartFishing 호출을 무시했습니다.");
return;
}
StopRunningRoutines();
if (uiRoot != null)
uiRoot.SetActive(true);
if (resetPondStateOnStart)
bool shouldResetPondState = forceRestart || resetPondStateOnStart;
if (fishingControlMode == FishingControlMode.SimpleReel && resetPondOnlyOnFirstSimpleReelStart)
shouldResetPondState = forceRestart || (resetPondStateOnStart && !simpleReelPondInitialized);
if (shouldResetPondState)
{
ResetPondState();
if (fishingControlMode == FishingControlMode.SimpleReel)
simpleReelPondInitialized = true;
}
fishingSessionRunning = true;
if (ui != null)
ui.InitializeFishingUI();
StartNewCatchAttempt();
if (fishingControlMode == FishingControlMode.SimpleReel)
StartSimpleReelCatch();
else
StartNewCatchAttempt();
if (showDebugLog)
Debug.Log("기묘한 낚시터 시작");
Debug.Log(fishingControlMode == FishingControlMode.SimpleReel ? "릴 감기 낚시 시작" : "기묘한 낚시터 시작");
}
public void StopFishing(bool hideUI = false)
@@ -325,6 +406,8 @@ public void StopFishing(bool hideUI = false)
activeGame = false;
inputLocked = true;
fishingSessionRunning = false;
simpleReelCatchActive = false;
if (centerIconRotate != null)
centerIconRotate.StopRotate();
@@ -335,7 +418,10 @@ public void StopFishing(bool hideUI = false)
public void ResetFishing()
{
StartFishing();
fishingSessionRunning = false;
simpleReelCatchActive = false;
simpleReelPondInitialized = false;
StartFishing(true);
}
public void ResetPondState()
@@ -350,6 +436,82 @@ public void ResetPondState()
sessionCompassCount = 0;
pondCleaned = false;
memoryPieceCollected = false;
simpleReelCatchActive = false;
simpleReelProgress = 0f;
simpleReelStartLineLength = 0f;
}
private void StartSimpleReelCatch()
{
if (rodController == null && autoBindMissingReferences)
AutoBindMissingReferences();
if (rodController == null)
{
Debug.LogWarning("[FishingGameManager] SimpleReel 모드에는 FishingRodVRController 참조가 필요합니다.", this);
activeGame = false;
inputLocked = true;
fishingSessionRunning = false;
return;
}
successCount = 0;
failCount = 0;
inputLocked = false;
activeGame = true;
simpleReelCatchActive = true;
float currentLineLength = Mathf.Max(rodController.CurrentLineLength, catchCompleteLineLength + simpleReelMinimumPullDistance);
simpleReelStartLineLength = currentLineLength;
simpleReelProgress = 0f;
if (centerIconRotate != null)
{
centerIconRotate.ResetRotation();
centerIconRotate.StopRotate();
}
if (ui != null)
{
ui.SetSimpleReelUIVisible(true);
if (hideTimingGaugeInSimpleReelMode)
ui.SetTimingGaugeVisible(false);
ui.UpdateSimpleReelUI(simpleReelProgress, rodController.CurrentLineLength, rodController.IsReeling);
ui.ShowPersistentResult("릴을 감아 끌어올려라!");
}
UpdateUI();
}
private void UpdateSimpleReelCatch()
{
if (!simpleReelCatchActive || rodController == null)
return;
float currentLineLength = rodController.CurrentLineLength;
float totalPullDistance = Mathf.Max(0.001f, simpleReelStartLineLength - catchCompleteLineLength);
float pulledDistance = simpleReelStartLineLength - currentLineLength;
simpleReelProgress = Mathf.Clamp01(pulledDistance / totalPullDistance);
if (ui != null)
ui.UpdateSimpleReelUI(simpleReelProgress, currentLineLength, rodController.IsReeling);
if (currentLineLength <= catchCompleteLineLength || simpleReelProgress >= 1f)
{
simpleReelCatchActive = false;
inputLocked = true;
if (haptic != null)
haptic.Perfect();
if (ui != null)
{
ui.UpdateSimpleReelUI(1f, currentLineLength, false);
ui.ShowPersistentResult("낚았다!");
}
CatchItemSuccess();
}
}
private void StartNewCatchAttempt()
@@ -366,7 +528,8 @@ private void StartNewCatchAttempt()
zoneSize = startZoneSize;
}
clockwise = UnityEngine.Random.value > 0.5f;
if (randomDirectionEachRound)
clockwise = UnityEngine.Random.value > 0.5f;
if (centerIconRotate != null)
{
@@ -412,6 +575,9 @@ private void RotatePointer()
public void SubmitAttempt()
{
if (fishingControlMode == FishingControlMode.SimpleReel)
return;
if (!activeGame)
return;
@@ -622,6 +788,17 @@ private void ApplyCatchResult(FishingRewardSystem.CatchResult catchResult)
return;
}
if (fishingControlMode == FishingControlMode.SimpleReel)
{
fishingSessionRunning = false;
simpleReelCatchActive = false;
if (returnBobberAfterSimpleReelCatch && rodController != null)
rodController.ReturnBobberToRest();
return;
}
nextCatchRoutine = StartCoroutine(NextCatchRoutine());
}
@@ -680,6 +857,23 @@ private void UpdateUI()
if (ui == null)
return;
if (fishingControlMode == FishingControlMode.SimpleReel)
{
ui.SetSimpleReelUIVisible(activeGame || simpleReelCatchActive);
if (hideTimingGaugeInSimpleReelMode)
ui.SetTimingGaugeVisible(false);
ui.UpdateFishingProgress(cleanupItemCount, requiredCleanupItems, pondCleaned, memoryPieceCollected, totalCaughtItems);
ui.UpdateInventoryUI(sessionFishCount, sessionTrashCount, sessionMemoryPieceCount, sessionCompassCount);
float currentLineLength = rodController != null ? rodController.CurrentLineLength : 0f;
bool isReeling = rodController != null && rodController.IsReeling;
ui.UpdateSimpleReelUI(simpleReelProgress, currentLineLength, isReeling);
return;
}
ui.SetSimpleReelUIVisible(false);
ui.SetTimingGaugeVisible(true);
ui.SetZone(zoneCenter, zoneSize);
ui.UpdateCounter(successCount, requiredSuccesses, failCount, allowedFails);
ui.UpdateFishingProgress(cleanupItemCount, requiredCleanupItems, pondCleaned, memoryPieceCollected, totalCaughtItems);
@@ -690,6 +884,8 @@ private void FishingSuccess()
{
activeGame = false;
inputLocked = true;
fishingSessionRunning = false;
simpleReelCatchActive = false;
if (centerIconRotate != null)
centerIconRotate.StopRotate();
@@ -709,6 +905,8 @@ private void FishingFail()
{
activeGame = false;
inputLocked = true;
fishingSessionRunning = false;
simpleReelCatchActive = false;
if (centerIconRotate != null)
centerIconRotate.StopRotate();