358 lines
7.6 KiB
C#
358 lines
7.6 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
public class FishingGameManager : MonoBehaviour
|
|
{
|
|
public enum ResultType
|
|
{
|
|
Perfect,
|
|
Good,
|
|
Miss
|
|
}
|
|
|
|
[Header("References")]
|
|
[SerializeField] private FishingGaugeUI ui;
|
|
[SerializeField] private FishingRewardSystem rewardSystem;
|
|
[SerializeField] private FishingHapticManager haptic;
|
|
[SerializeField] private RotateUI centerIconRotate;
|
|
|
|
[Header("Pointer")]
|
|
[SerializeField] private float pointerAngle;
|
|
[SerializeField] private float pointerSpeed = 180f;
|
|
[SerializeField] private float minSpeed = 180f;
|
|
[SerializeField] private float maxSpeed = 450f;
|
|
|
|
[Header("Zone")]
|
|
[SerializeField] private float startZoneSize = 90f;
|
|
[SerializeField] private float zoneSize = 90f;
|
|
[SerializeField] private float minZoneSize = 30f;
|
|
[SerializeField] private float maxZoneSize = 120f;
|
|
[SerializeField] private float zoneCenter;
|
|
|
|
[Header("Rules")]
|
|
[SerializeField] private int requiredSuccesses = 3;
|
|
[SerializeField] private int allowedFails = 3;
|
|
|
|
[Header("Round Settings")]
|
|
[SerializeField] private float nextRoundDelay = 0.35f;
|
|
[SerializeField] private bool randomDirectionEachRound = true;
|
|
[SerializeField] private bool startOnAwake = true;
|
|
|
|
[Header("Debug")]
|
|
[SerializeField] private bool showDebugLog = true;
|
|
|
|
private int successCount;
|
|
private int failCount;
|
|
|
|
private bool clockwise = true;
|
|
private bool activeGame;
|
|
private bool inputLocked;
|
|
|
|
private Coroutine nextRoundRoutine;
|
|
|
|
private void Start()
|
|
{
|
|
if (startOnAwake)
|
|
{
|
|
StartFishing();
|
|
}
|
|
else
|
|
{
|
|
InitializeIdleUI();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!activeGame)
|
|
return;
|
|
|
|
if (inputLocked)
|
|
return;
|
|
|
|
RotatePointer();
|
|
}
|
|
|
|
private void InitializeIdleUI()
|
|
{
|
|
if (ui != null)
|
|
{
|
|
ui.HideRoundResult();
|
|
ui.HideFinalResult();
|
|
ui.UpdateCounter(0, requiredSuccesses, 0, allowedFails);
|
|
ui.SetPointerRotation(0f);
|
|
ui.SetZone(0f, startZoneSize);
|
|
}
|
|
|
|
if (centerIconRotate != null)
|
|
centerIconRotate.StopRotate();
|
|
}
|
|
|
|
public void StartFishing()
|
|
{
|
|
if (nextRoundRoutine != null)
|
|
{
|
|
StopCoroutine(nextRoundRoutine);
|
|
nextRoundRoutine = null;
|
|
}
|
|
|
|
successCount = 0;
|
|
failCount = 0;
|
|
|
|
pointerAngle = 0f;
|
|
pointerSpeed = minSpeed;
|
|
zoneSize = startZoneSize;
|
|
|
|
activeGame = true;
|
|
inputLocked = false;
|
|
|
|
clockwise = Random.value > 0.5f;
|
|
|
|
if (ui != null)
|
|
{
|
|
ui.HideRoundResult();
|
|
ui.HideFinalResult();
|
|
}
|
|
|
|
if (centerIconRotate != null)
|
|
{
|
|
centerIconRotate.ResetRotation();
|
|
centerIconRotate.StartRotate();
|
|
}
|
|
|
|
RandomizeZone();
|
|
UpdateUI();
|
|
|
|
if (showDebugLog)
|
|
Debug.Log("낚시 시작");
|
|
}
|
|
|
|
private void RotatePointer()
|
|
{
|
|
float dir = clockwise ? 1f : -1f;
|
|
|
|
pointerAngle += dir * pointerSpeed * Time.deltaTime;
|
|
pointerAngle = Normalize(pointerAngle);
|
|
|
|
if (ui != null)
|
|
ui.SetPointerRotation(pointerAngle);
|
|
}
|
|
|
|
public void SubmitAttempt()
|
|
{
|
|
if (!activeGame)
|
|
return;
|
|
|
|
if (inputLocked)
|
|
return;
|
|
|
|
inputLocked = true;
|
|
|
|
ResultType result = EvaluateResult();
|
|
|
|
switch (result)
|
|
{
|
|
case ResultType.Perfect:
|
|
OnPerfect();
|
|
break;
|
|
|
|
case ResultType.Good:
|
|
OnGood();
|
|
break;
|
|
|
|
case ResultType.Miss:
|
|
OnMiss();
|
|
break;
|
|
}
|
|
|
|
if (successCount >= requiredSuccesses)
|
|
{
|
|
FishingSuccess();
|
|
return;
|
|
}
|
|
|
|
if (failCount >= allowedFails)
|
|
{
|
|
FishingFail();
|
|
return;
|
|
}
|
|
|
|
nextRoundRoutine = StartCoroutine(NextRoundRoutine());
|
|
}
|
|
|
|
private ResultType EvaluateResult()
|
|
{
|
|
float delta = Mathf.Abs(Mathf.DeltaAngle(pointerAngle, zoneCenter));
|
|
|
|
float perfectRange = zoneSize * 0.2f;
|
|
float goodRange = zoneSize * 0.5f;
|
|
|
|
if (delta <= perfectRange)
|
|
return ResultType.Perfect;
|
|
|
|
if (delta <= goodRange)
|
|
return ResultType.Good;
|
|
|
|
return ResultType.Miss;
|
|
}
|
|
|
|
private void OnPerfect()
|
|
{
|
|
successCount++;
|
|
|
|
zoneSize *= 0.9f;
|
|
pointerSpeed *= 1.05f;
|
|
|
|
if (haptic != null)
|
|
haptic.Perfect();
|
|
|
|
if (ui != null)
|
|
ui.ShowResult("완벽!");
|
|
|
|
if (showDebugLog)
|
|
Debug.Log("낚시 판정: Perfect");
|
|
|
|
ClampDifficulty();
|
|
UpdateUI();
|
|
}
|
|
|
|
private void OnGood()
|
|
{
|
|
successCount++;
|
|
|
|
zoneSize *= 0.95f;
|
|
pointerSpeed *= 1.02f;
|
|
|
|
if (haptic != null)
|
|
haptic.Good();
|
|
|
|
if (ui != null)
|
|
ui.ShowResult("성공!");
|
|
|
|
if (showDebugLog)
|
|
Debug.Log("낚시 판정: Good");
|
|
|
|
ClampDifficulty();
|
|
UpdateUI();
|
|
}
|
|
|
|
private void OnMiss()
|
|
{
|
|
failCount++;
|
|
|
|
zoneSize *= 1.05f;
|
|
pointerSpeed *= 0.95f;
|
|
|
|
if (haptic != null)
|
|
haptic.Miss();
|
|
|
|
if (ui != null)
|
|
ui.ShowResult("실패!");
|
|
|
|
if (showDebugLog)
|
|
Debug.Log("낚시 판정: Miss");
|
|
|
|
ClampDifficulty();
|
|
UpdateUI();
|
|
}
|
|
|
|
private IEnumerator NextRoundRoutine()
|
|
{
|
|
yield return new WaitForSeconds(nextRoundDelay);
|
|
|
|
if (!activeGame)
|
|
yield break;
|
|
|
|
if (randomDirectionEachRound)
|
|
clockwise = Random.value > 0.5f;
|
|
|
|
RandomizeZone();
|
|
UpdateUI();
|
|
|
|
inputLocked = false;
|
|
nextRoundRoutine = null;
|
|
}
|
|
|
|
private void ClampDifficulty()
|
|
{
|
|
zoneSize = Mathf.Clamp(zoneSize, minZoneSize, maxZoneSize);
|
|
pointerSpeed = Mathf.Clamp(pointerSpeed, minSpeed, maxSpeed);
|
|
}
|
|
|
|
private void RandomizeZone()
|
|
{
|
|
zoneCenter = Random.Range(0f, 360f);
|
|
}
|
|
|
|
private void UpdateUI()
|
|
{
|
|
if (ui == null)
|
|
return;
|
|
|
|
ui.SetZone(zoneCenter, zoneSize);
|
|
ui.UpdateCounter(successCount, requiredSuccesses, failCount, allowedFails);
|
|
}
|
|
|
|
private void FishingSuccess()
|
|
{
|
|
activeGame = false;
|
|
inputLocked = true;
|
|
|
|
if (centerIconRotate != null)
|
|
centerIconRotate.StopRotate();
|
|
|
|
if (ui != null)
|
|
ui.ShowFinalResult("낚시 성공!");
|
|
|
|
if (rewardSystem != null)
|
|
rewardSystem.GiveReward();
|
|
|
|
if (showDebugLog)
|
|
Debug.Log("낚시 최종 성공");
|
|
}
|
|
|
|
private void FishingFail()
|
|
{
|
|
activeGame = false;
|
|
inputLocked = true;
|
|
|
|
if (centerIconRotate != null)
|
|
centerIconRotate.StopRotate();
|
|
|
|
if (ui != null)
|
|
ui.ShowFinalResult("낚시 실패!");
|
|
|
|
if (showDebugLog)
|
|
Debug.Log("낚시 최종 실패");
|
|
}
|
|
|
|
public void ResetFishing()
|
|
{
|
|
StartFishing();
|
|
}
|
|
|
|
private float Normalize(float angle)
|
|
{
|
|
angle %= 360f;
|
|
|
|
if (angle < 0f)
|
|
angle += 360f;
|
|
|
|
return angle;
|
|
}
|
|
|
|
// XR Input Action의 Select / Trigger 버튼에 연결
|
|
public void OnSubmit(InputValue value)
|
|
{
|
|
if (value.isPressed)
|
|
SubmitAttempt();
|
|
}
|
|
|
|
// Reset 버튼에 연결 가능
|
|
public void OnReset(InputValue value)
|
|
{
|
|
if (value.isPressed)
|
|
ResetFishing();
|
|
}
|
|
} |