Files
WhaleAdventure_VR_Diet/Assets/My project/Fishing Scripts/UI/FishingGameManager.cs
2026-06-29 14:25:49 +09:00

815 lines
28 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
/// <summary>
/// Reel-only fishing game manager.
///
/// Removed from the old mixed version:
/// - TimingGauge mode enum
/// - Perfect / Good / Miss timing judgement
/// - pointer rotation / success zone / round retry logic
/// - submit action for the timing gauge
///
/// Flow:
/// FishingRodVRController detects bite -> StartFishing()
/// -> player reels in -> CurrentLineLength reaches catchCompleteLineLength
/// -> reward is rolled -> UI/inventory event updates -> bobber returns.
/// </summary>
public class FishingGameManager : MonoBehaviour
{
[Header("Auto Bind")]
[Tooltip("현재 만든 Prefab 구조 기준으로 비어 있는 참조를 자동 연결합니다.")]
[SerializeField] private bool autoBindMissingReferences = true;
[Header("References")]
[Tooltip("낚시 UI 전체 루트입니다. UI를 자동으로 켜고 끄고 싶을 때만 연결하세요.")]
[SerializeField] private GameObject uiRoot;
[SerializeField] private FishingGaugeUI ui;
[SerializeField] private FishingRewardSystem rewardSystem;
[SerializeField] private FishingHapticManager haptic;
[SerializeField] private FishingRodVRController rodController;
[SerializeField] private GameClear gameClear;
[Header("Memory Piece Result Object")]
[Tooltip("기억의 조각 획득 결과창이 뜰 때 플레이어 화면 앞에 생성할 오브젝트 프리팹입니다. StarPickup이 붙어 있어도 됩니다.")]
[SerializeField] private GameObject memoryPieceResultPrefab;
[Tooltip("씬에 미리 배치해 둔 기억의 조각 오브젝트입니다. 비워두면 Prefab을 생성합니다.")]
[SerializeField] private GameObject memoryPieceResultSceneObject;
[Tooltip("XR Origin의 Main Camera를 넣으세요. 비워두면 Camera.main을 자동으로 사용합니다.")]
[SerializeField] private Transform memoryPiecePlayerHead;
[SerializeField] private float memoryPieceResultDistance = 1.2f;
[SerializeField] private float memoryPieceResultHeightOffset = -0.05f;
[SerializeField] private float memoryPieceResultSideOffset = 0f;
[SerializeField] private bool memoryPieceResultFollowPlayerHead = true;
[SerializeField] private bool memoryPieceResultYawOnly = true;
[Tooltip("켜면 오브젝트가 플레이어를 바라보게 합니다. StarPickup의 visualRoot가 자기 자신이면 회전 연출이 덮일 수 있으니 기본값은 Off입니다.")]
[SerializeField] private bool memoryPieceResultFacePlayer = false;
[Tooltip("0보다 크면 이 시간 뒤 기억의 조각 오브젝트를 숨깁니다. 결과창 자동 닫기 시간과 비슷하게 맞추세요.")]
[SerializeField] private float memoryPieceResultShowTime = 3f;
[SerializeField] private bool memoryPieceResultUseCustomScale = false;
[SerializeField] private Vector3 memoryPieceResultCustomScale = Vector3.one;
[Tooltip("켜면 StarPickup Trigger로 플레이어가 닿자마자 수집/Destroy되는 것을 막기 위해 Collider를 꺼둡니다.")]
[SerializeField] private bool disableMemoryPieceResultColliders = true;
[Tooltip("켜면 StarPickup의 floatMotion을 꺼서 카메라 앞 고정 위치와 충돌하지 않게 합니다. 회전은 유지됩니다.")]
[SerializeField] private bool disableMemoryPieceResultFloatMotion = true;
[SerializeField] private bool destroySpawnedMemoryPieceResultOnHide = true;
[Header("Reel Fishing")]
[Tooltip("현재 줄 길이가 이 값 이하가 되면 낚기 성공으로 처리합니다.")]
[SerializeField] private float catchCompleteLineLength = 0.7f;
[Tooltip("릴 낚시 시작 시 줄 길이가 성공 길이보다 너무 짧으면 이 거리만큼 최소 시작 길이를 보정합니다.")]
[SerializeField] private float simpleReelMinimumPullDistance = 0.35f;
[Tooltip("릴 낚기 성공 후 찌를 낚싯대 쪽 대기 위치로 회수합니다.")]
[SerializeField] private bool returnBobberAfterCatch = true;
[Tooltip("SimpleReel 모드에서는 StartFishing이 입질마다 호출됩니다. 켜면 첫 시작 때만 연못 상태를 초기화합니다.")]
[SerializeField] private bool resetPondOnlyOnFirstStart = true;
[Header("Reset Input")]
[Tooltip("낚시 상태를 다시 시작할 컨트롤러 입력입니다. 필요 없으면 비워둬도 됩니다.")]
[SerializeField] private InputActionReference resetAction;
[Tooltip("씬에 Input Action Manager가 없거나 액션이 자동 활성화되지 않으면 켜두세요.")]
[SerializeField] private bool enableInputActionsManually = true;
[Header("Pond Cleanup Rules")]
[Tooltip("연못을 맑게 만들기 위해 필요한 쓰레기 수입니다. 이제 쓰레기만 정화 아이템으로 카운트됩니다.")]
[SerializeField] private int requiredCleanupItems = 3;
[Tooltip("연못이 맑아진 뒤 다음 성공 낚시에서 기억의 조각을 확정으로 낚습니다.")]
[SerializeField] private bool guaranteeMemoryPieceAfterCleaned = true;
[Tooltip("StartFishing을 호출할 때 쓰레기 수거/연못 상태를 초기화합니다.")]
[SerializeField] private bool resetPondStateOnStart = true;
[Tooltip("낚시 세션이 진행 중일 때 StartFishing이 중복 호출되는 것을 막습니다.")]
[SerializeField] private bool preventRestartWhileSessionRunning = true;
[Header("Start / Final Result")]
[Tooltip("VR 릴 낚시에서는 보통 꺼두세요. 입질이 왔을 때 FishingRodVRController가 StartFishing을 호출하는 구조를 추천합니다.")]
[SerializeField] private bool startOnAwake = false;
[Tooltip("최종 결과를 잠깐 보여준 뒤 uiRoot를 자동으로 끕니다. uiRoot가 비어 있으면 동작하지 않습니다.")]
[SerializeField] private bool hideUIRootAfterFinalResult = false;
[SerializeField] private float finalResultShowTime = 1.5f;
[Header("Debug")]
[SerializeField] private bool showDebugLog = true;
private int cleanupItemCount;
private int totalCaughtItems;
// 임시 낚시 세션 카운트입니다. 영구 저장은 FishingInventoryBinder를 통해 FishingInventory에 연결하세요.
private int sessionFishCount;
private int sessionTrashCount;
private int sessionMemoryPieceCount;
private bool activeGame;
private bool fishingSessionRunning;
private bool pondCleaned;
private bool memoryPieceCollected;
private bool simpleReelCatchActive;
private bool pondInitialized;
private float simpleReelStartLineLength;
private float simpleReelProgress;
private bool resetActionWasEnabled;
private Coroutine finalResultRoutine;
private Coroutine memoryPieceResultRoutine;
private GameObject currentMemoryPieceResultObject;
private bool memoryPieceResultShowing;
public bool IsActiveGame => activeGame;
public bool IsFishingSessionRunning => fishingSessionRunning;
public bool IsPondCleaned => pondCleaned;
public bool IsMemoryPieceCollected => memoryPieceCollected;
public int CleanupItemCount => cleanupItemCount;
public int RequiredCleanupItems => requiredCleanupItems;
public int TotalCaughtItems => totalCaughtItems;
public int SessionFishCount => sessionFishCount;
public int SessionTrashCount => sessionTrashCount;
public int SessionMemoryPieceCount => sessionMemoryPieceCount;
public bool IsSimpleReelCatchActive => simpleReelCatchActive;
public float SimpleReelProgress => simpleReelProgress;
public event Action<FishingItemType, int> ItemCaught;
private void OnEnable()
{
RegisterInputAction(resetAction, OnResetAction, ref resetActionWasEnabled);
}
private void OnDisable()
{
UnregisterInputAction(resetAction, OnResetAction, resetActionWasEnabled);
}
private void Start()
{
if (autoBindMissingReferences)
AutoBindMissingReferences();
ValidateRuntimeSettings();
if (startOnAwake)
StartFishing();
else
InitializeIdleUI();
}
private void Update()
{
if (!activeGame)
return;
UpdateSimpleReelCatch();
}
private void LateUpdate()
{
UpdateMemoryPieceResultFollow();
}
private void OnValidate()
{
ValidateRuntimeSettings();
}
[ContextMenu("Auto Bind Fishing References")]
public void AutoBindMissingReferences()
{
Transform searchRoot = GetSearchRoot();
if (uiRoot == null)
{
Transform canvasTransform = FindTransformRecursive(searchRoot, "FishingCanvas");
if (canvasTransform != null)
uiRoot = canvasTransform.gameObject;
}
if (ui == null)
ui = searchRoot != null ? searchRoot.GetComponentInChildren<FishingGaugeUI>(true) : GetComponentInChildren<FishingGaugeUI>(true);
if (rewardSystem == null)
rewardSystem = searchRoot != null ? searchRoot.GetComponentInChildren<FishingRewardSystem>(true) : GetComponentInChildren<FishingRewardSystem>(true);
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 (gameClear == null)
gameClear = searchRoot != null ? searchRoot.GetComponentInChildren<GameClear>(true) : GetComponentInChildren<GameClear>(true);
if (memoryPieceResultSceneObject == null)
{
Transform memoryPieceResultTransform = FindTransformRecursive(searchRoot, "MemoryPieceResultObject");
if (memoryPieceResultTransform == null)
memoryPieceResultTransform = FindTransformRecursive(searchRoot, "MemoryPieceScreenObject");
if (memoryPieceResultTransform == null)
memoryPieceResultTransform = FindTransformRecursive(searchRoot, "MemoryPieceResultVisual");
if (memoryPieceResultTransform != null)
memoryPieceResultSceneObject = memoryPieceResultTransform.gameObject;
}
}
private Transform GetSearchRoot()
{
Transform current = transform;
while (current.parent != null)
current = current.parent;
return current;
}
private Transform FindTransformRecursive(Transform current, string targetName)
{
if (current == null || string.IsNullOrEmpty(targetName))
return null;
if (NormalizeName(current.name) == NormalizeName(targetName))
return current;
for (int i = 0; i < current.childCount; i++)
{
Transform found = FindTransformRecursive(current.GetChild(i), targetName);
if (found != null)
return found;
}
return null;
}
private string NormalizeName(string value)
{
return value.Replace(" ", string.Empty)
.Replace("_", string.Empty)
.Replace("-", string.Empty)
.ToLowerInvariant();
}
private void RegisterInputAction(InputActionReference actionReference, System.Action<InputAction.CallbackContext> callback, ref bool wasEnabled)
{
if (actionReference == null || actionReference.action == null)
return;
wasEnabled = actionReference.action.enabled;
actionReference.action.performed += callback;
if (enableInputActionsManually && !wasEnabled)
actionReference.action.Enable();
}
private void UnregisterInputAction(InputActionReference actionReference, System.Action<InputAction.CallbackContext> callback, bool wasEnabled)
{
if (actionReference == null || actionReference.action == null)
return;
actionReference.action.performed -= callback;
if (enableInputActionsManually && !wasEnabled)
actionReference.action.Disable();
}
private void ValidateRuntimeSettings()
{
requiredCleanupItems = Mathf.Max(1, requiredCleanupItems);
catchCompleteLineLength = Mathf.Max(0.05f, catchCompleteLineLength);
simpleReelMinimumPullDistance = Mathf.Max(0.01f, simpleReelMinimumPullDistance);
finalResultShowTime = Mathf.Max(0f, finalResultShowTime);
memoryPieceResultDistance = Mathf.Max(0.1f, memoryPieceResultDistance);
memoryPieceResultShowTime = Mathf.Max(0f, memoryPieceResultShowTime);
cleanupItemCount = Mathf.Max(0, cleanupItemCount);
totalCaughtItems = Mathf.Max(0, totalCaughtItems);
}
private void InitializeIdleUI()
{
if (ui == null)
return;
ui.InitializeFishingUI();
ui.UpdateFishingProgress(cleanupItemCount, requiredCleanupItems, pondCleaned, memoryPieceCollected, totalCaughtItems);
ui.UpdateInventoryUI(sessionFishCount, sessionTrashCount, sessionMemoryPieceCount);
ui.SetSimpleReelUIVisible(false);
ui.UpdateSimpleReelUI(0f, rodController != null ? rodController.CurrentLineLength : 0f, false);
}
public void StartFishing()
{
StartFishing(false);
}
public void StartFishing(bool forceRestart)
{
ValidateRuntimeSettings();
if (preventRestartWhileSessionRunning && fishingSessionRunning && !forceRestart)
{
if (showDebugLog)
Debug.Log("낚시 세션이 이미 진행 중이라 StartFishing 호출을 무시했습니다.", this);
return;
}
StopRunningRoutines();
if (uiRoot != null)
uiRoot.SetActive(true);
bool shouldResetPondState = forceRestart || resetPondStateOnStart;
if (resetPondOnlyOnFirstStart)
shouldResetPondState = forceRestart || (resetPondStateOnStart && !pondInitialized);
if (shouldResetPondState)
{
ResetPondState();
pondInitialized = true;
}
fishingSessionRunning = true;
if (ui != null)
ui.InitializeFishingUI();
StartSimpleReelCatch();
if (showDebugLog)
Debug.Log("릴 감기 낚시 시작", this);
}
public void StopFishing(bool hideUI = false)
{
StopRunningRoutines();
activeGame = false;
fishingSessionRunning = false;
simpleReelCatchActive = false;
simpleReelProgress = 0f;
if (ui != null)
ui.SetSimpleReelUIVisible(false);
if (hideUI && uiRoot != null)
uiRoot.SetActive(false);
}
public void ResetFishing()
{
fishingSessionRunning = false;
simpleReelCatchActive = false;
pondInitialized = false;
StartFishing(true);
}
public void ResetPondState()
{
cleanupItemCount = 0;
totalCaughtItems = 0;
sessionFishCount = 0;
sessionTrashCount = 0;
sessionMemoryPieceCount = 0;
pondCleaned = false;
memoryPieceCollected = false;
simpleReelCatchActive = false;
simpleReelProgress = 0f;
simpleReelStartLineLength = 0f;
HideMemoryPieceResultObject();
}
private void StartSimpleReelCatch()
{
if (rodController == null && autoBindMissingReferences)
AutoBindMissingReferences();
if (rodController == null)
{
Debug.LogWarning("[FishingGameManager] 릴 감기 낚시에는 FishingRodVRController 참조가 필요합니다.", this);
activeGame = false;
fishingSessionRunning = false;
simpleReelCatchActive = false;
return;
}
activeGame = true;
simpleReelCatchActive = true;
// 중요: 기존 코드에서는 simpleReelStartLineLength만 보정하고 실제 줄 길이는 그대로라서
// 찌가 대기 위치에 있으면 시작 즉시 성공할 수 있었습니다.
// 릴 전용 버전에서는 실제 줄 길이도 최소 시작 길이로 맞춥니다.
float minimumStartLength = catchCompleteLineLength + simpleReelMinimumPullDistance;
if (rodController.CurrentLineLength < minimumStartLength)
rodController.ForceSetReelLineLength(minimumStartLength);
rodController.ForceMiniGameActiveState();
simpleReelStartLineLength = Mathf.Max(rodController.CurrentLineLength, minimumStartLength);
simpleReelProgress = 0f;
if (ui != null)
{
ui.SetSimpleReelUIVisible(true);
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;
activeGame = false;
if (haptic != null)
haptic.Perfect();
if (ui != null)
{
ui.UpdateSimpleReelUI(1f, currentLineLength, false);
ui.ShowPersistentResult("낚았다!");
}
CatchItemSuccess();
}
}
private void StopRunningRoutines()
{
if (finalResultRoutine != null)
{
StopCoroutine(finalResultRoutine);
finalResultRoutine = null;
}
if (memoryPieceResultRoutine != null)
{
StopCoroutine(memoryPieceResultRoutine);
memoryPieceResultRoutine = null;
}
HideMemoryPieceResultObject();
}
private void CatchItemSuccess()
{
bool forceMemoryPiece = pondCleaned && guaranteeMemoryPieceAfterCleaned && !memoryPieceCollected;
FishingRewardSystem.CatchResult catchResult;
if (rewardSystem != null)
catchResult = rewardSystem.RollCatch(pondCleaned, forceMemoryPiece);
else
catchResult = new FishingRewardSystem.CatchResult(FishingItemType.Fish, "물고기", false, false);
ApplyCatchResult(catchResult);
}
private void ApplyCatchResult(FishingRewardSystem.CatchResult catchResult)
{
totalCaughtItems++;
AddToSessionCounts(catchResult.ItemType);
ItemCaught?.Invoke(catchResult.ItemType, 1);
bool pondJustCleaned = false;
string extraHint = string.Empty;
if (catchResult.CountsAsCleanupItem)
{
cleanupItemCount = Mathf.Min(cleanupItemCount + 1, requiredCleanupItems);
extraHint = $"연못 정화 {cleanupItemCount}/{requiredCleanupItems}";
if (!pondCleaned && cleanupItemCount >= requiredCleanupItems)
{
pondCleaned = true;
pondJustCleaned = true;
extraHint = "연못이 맑아졌다. 기억의 조각이 모습을 드러낸다.";
}
}
if (catchResult.IsMemoryPiece)
{
memoryPieceCollected = true;
extraHint = "잃어버린 기억의 일부다.";
}
UpdateUI();
if (ui != null)
{
ui.HighlightSlotForItem(catchResult.ItemType);
if (!catchResult.IsMemoryPiece)
ui.ShowCaughtItem(catchResult.ItemType, catchResult.DisplayName, catchResult.CountsAsCleanupItem, extraHint);
if (pondJustCleaned)
ui.ShowNotice("연못이 맑아졌다!\n기억의 조각이 모습을 드러냈다!");
}
if (showDebugLog)
Debug.Log($"{catchResult.DisplayName}을(를) 낚았다!", this);
fishingSessionRunning = false;
simpleReelCatchActive = false;
activeGame = false;
if (returnBobberAfterCatch && rodController != null)
rodController.ReturnBobberToRest();
if (catchResult.IsMemoryPiece)
FishingSuccess();
}
private void AddToSessionCounts(FishingItemType itemType)
{
switch (itemType)
{
case FishingItemType.Fish:
sessionFishCount++;
break;
case FishingItemType.Trash:
sessionTrashCount++;
break;
case FishingItemType.MemoryPiece:
sessionMemoryPieceCount++;
break;
}
}
private void UpdateUI()
{
if (ui == null)
return;
ui.SetSimpleReelUIVisible(activeGame || simpleReelCatchActive);
ui.UpdateFishingProgress(cleanupItemCount, requiredCleanupItems, pondCleaned, memoryPieceCollected, totalCaughtItems);
ui.UpdateInventoryUI(sessionFishCount, sessionTrashCount, sessionMemoryPieceCount);
float currentLineLength = rodController != null ? rodController.CurrentLineLength : 0f;
bool isReeling = rodController != null && rodController.IsReeling;
ui.UpdateSimpleReelUI(simpleReelProgress, currentLineLength, isReeling);
}
private void FishingSuccess()
{
activeGame = false;
fishingSessionRunning = false;
simpleReelCatchActive = false;
UpdateUI();
if (ui != null)
ui.ShowFinalResult("기억의 조각 획득!\n기묘한 낚시터 클리어!");
ShowMemoryPieceResultObject();
if (gameClear != null)
{
gameClear.OnGameClear();
}
else if (showDebugLog)
{
Debug.LogWarning("[FishingGameManager] GameClear가 연결되지 않아 NPC 이동/대화존 변경/문 선택지 세팅을 실행하지 못했습니다.", this);
}
if (showDebugLog)
Debug.Log("기묘한 낚시터 클리어", this);
BeginFinalResultRoutineIfNeeded();
}
private void BeginFinalResultRoutineIfNeeded()
{
if (!hideUIRootAfterFinalResult || uiRoot == null)
return;
if (finalResultRoutine != null)
StopCoroutine(finalResultRoutine);
finalResultRoutine = StartCoroutine(HideUIRootAfterFinalResultRoutine());
}
private IEnumerator HideUIRootAfterFinalResultRoutine()
{
yield return new WaitForSeconds(finalResultShowTime);
if (uiRoot != null)
uiRoot.SetActive(false);
HideMemoryPieceResultObject();
finalResultRoutine = null;
}
private void ShowMemoryPieceResultObject()
{
EnsureMemoryPiecePlayerHead();
if (memoryPiecePlayerHead == null)
{
Debug.LogWarning("[FishingGameManager] Memory Piece Player Head가 없습니다. XR Origin의 Main Camera를 연결하세요.", this);
return;
}
if (memoryPieceResultRoutine != null)
{
StopCoroutine(memoryPieceResultRoutine);
memoryPieceResultRoutine = null;
}
if (currentMemoryPieceResultObject != null && currentMemoryPieceResultObject != memoryPieceResultSceneObject)
{
Destroy(currentMemoryPieceResultObject);
currentMemoryPieceResultObject = null;
}
if (memoryPieceResultSceneObject != null)
{
currentMemoryPieceResultObject = memoryPieceResultSceneObject;
}
else if (memoryPieceResultPrefab != null)
{
currentMemoryPieceResultObject = Instantiate(memoryPieceResultPrefab);
}
else
{
if (showDebugLog)
Debug.LogWarning("[FishingGameManager] Memory Piece Result Prefab 또는 Scene Object가 연결되지 않았습니다.", this);
return;
}
currentMemoryPieceResultObject.SetActive(true);
if (memoryPieceResultUseCustomScale)
currentMemoryPieceResultObject.transform.localScale = memoryPieceResultCustomScale;
PrepareMemoryPieceResultObject(currentMemoryPieceResultObject);
PlaceMemoryPieceResultObjectInFrontOfPlayer();
memoryPieceResultShowing = true;
if (memoryPieceResultShowTime > 0f)
memoryPieceResultRoutine = StartCoroutine(HideMemoryPieceResultObjectAfterDelay());
}
private void HideMemoryPieceResultObject()
{
memoryPieceResultShowing = false;
if (memoryPieceResultRoutine != null)
{
StopCoroutine(memoryPieceResultRoutine);
memoryPieceResultRoutine = null;
}
if (currentMemoryPieceResultObject == null)
return;
if (currentMemoryPieceResultObject == memoryPieceResultSceneObject)
{
currentMemoryPieceResultObject.SetActive(false);
}
else if (destroySpawnedMemoryPieceResultOnHide)
{
Destroy(currentMemoryPieceResultObject);
}
else
{
currentMemoryPieceResultObject.SetActive(false);
}
currentMemoryPieceResultObject = null;
}
private IEnumerator HideMemoryPieceResultObjectAfterDelay()
{
yield return new WaitForSeconds(memoryPieceResultShowTime);
memoryPieceResultRoutine = null;
HideMemoryPieceResultObject();
}
private void UpdateMemoryPieceResultFollow()
{
if (!memoryPieceResultShowing || !memoryPieceResultFollowPlayerHead || currentMemoryPieceResultObject == null)
return;
PlaceMemoryPieceResultObjectInFrontOfPlayer();
}
private void EnsureMemoryPiecePlayerHead()
{
if (memoryPiecePlayerHead != null)
return;
Camera mainCamera = Camera.main;
if (mainCamera != null)
memoryPiecePlayerHead = mainCamera.transform;
}
private void PlaceMemoryPieceResultObjectInFrontOfPlayer()
{
if (memoryPiecePlayerHead == null || currentMemoryPieceResultObject == null)
return;
Vector3 forward = memoryPiecePlayerHead.forward;
Vector3 right = memoryPiecePlayerHead.right;
if (memoryPieceResultYawOnly)
{
forward.y = 0f;
if (forward.sqrMagnitude < 0.0001f)
forward = currentMemoryPieceResultObject.transform.forward;
forward.Normalize();
right = Vector3.Cross(Vector3.up, forward).normalized;
}
Vector3 targetPosition =
memoryPiecePlayerHead.position +
forward * memoryPieceResultDistance +
Vector3.up * memoryPieceResultHeightOffset +
right * memoryPieceResultSideOffset;
currentMemoryPieceResultObject.transform.position = targetPosition;
if (!memoryPieceResultFacePlayer)
return;
Vector3 lookDirection = memoryPiecePlayerHead.position - currentMemoryPieceResultObject.transform.position;
if (memoryPieceResultYawOnly)
lookDirection.y = 0f;
if (lookDirection.sqrMagnitude > 0.0001f)
currentMemoryPieceResultObject.transform.rotation = Quaternion.LookRotation(lookDirection.normalized, Vector3.up);
}
private void PrepareMemoryPieceResultObject(GameObject target)
{
if (target == null)
return;
if (disableMemoryPieceResultColliders)
{
Collider[] colliders = target.GetComponentsInChildren<Collider>(true);
for (int i = 0; i < colliders.Length; i++)
colliders[i].enabled = false;
}
if (disableMemoryPieceResultFloatMotion)
{
StarPickup[] starPickups = target.GetComponentsInChildren<StarPickup>(true);
for (int i = 0; i < starPickups.Length; i++)
starPickups[i].floatMotion = false;
}
}
private void OnResetAction(InputAction.CallbackContext context)
{
ResetFishing();
}
}