316 lines
8.2 KiB
C#
316 lines
8.2 KiB
C#
using System.Threading;
|
|
using BriarQueen.Framework.Managers.Levels.Data;
|
|
using BriarQueen.Framework.Managers.Player.Data;
|
|
using Cysharp.Threading.Tasks;
|
|
using PrimeTween;
|
|
using UnityEngine;
|
|
|
|
namespace BriarQueen.Game.Puzzles.ChapterOne.LaxleyHouse.Clock
|
|
{
|
|
public class LaxleyClockHand : BaseItem
|
|
{
|
|
[Header("State")]
|
|
[SerializeField]
|
|
private bool _placed;
|
|
|
|
[SerializeField]
|
|
[Range(0, 11)]
|
|
private int _currentRotationStep;
|
|
|
|
[SerializeField]
|
|
private bool _locked;
|
|
|
|
[SerializeField]
|
|
private bool _isRotating;
|
|
|
|
[SerializeField]
|
|
private bool _canRotate;
|
|
|
|
[Header("Rotation")]
|
|
[SerializeField]
|
|
private float[] _rotationSteps = new float[12]
|
|
{
|
|
0f, // 12
|
|
-30f, // 1
|
|
-60f, // 2
|
|
-90f, // 3
|
|
-120f, // 4
|
|
-150f, // 5
|
|
-180f, // 6
|
|
-210f, // 7
|
|
-240f, // 8
|
|
-270f, // 9
|
|
-300f, // 10
|
|
-330f // 11
|
|
};
|
|
|
|
[SerializeField]
|
|
private float _rotateDuration = 0.15f;
|
|
|
|
[SerializeField]
|
|
private Ease _rotateEase = Ease.Linear;
|
|
|
|
[Header("Placement")]
|
|
[SerializeField]
|
|
private float _placeDuration = 0.2f;
|
|
|
|
[SerializeField]
|
|
private Ease _placeEase = Ease.OutSine;
|
|
|
|
[Header("Components")]
|
|
[SerializeField]
|
|
private GameObject _parentPivot;
|
|
|
|
[SerializeField]
|
|
private CanvasGroup _parentCanvasGroup;
|
|
|
|
[Header("Placement Behaviour")]
|
|
[SerializeField]
|
|
private bool _randomiseRotationOnFirstPlace = true;
|
|
|
|
private Sequence _placeSequence;
|
|
private Sequence _rotateSequence;
|
|
|
|
private CancellationTokenSource _placeCTS;
|
|
private CancellationTokenSource _rotateCTS;
|
|
|
|
private LaxleyClockFace _clockFace;
|
|
|
|
public bool Placed => _placed;
|
|
public int CurrentRotationStep => _currentRotationStep;
|
|
|
|
public void Initialise(LaxleyClockFace clockFace, LaxleyClockBasePuzzle owningPuzzle)
|
|
{
|
|
_clockFace = clockFace;
|
|
_canRotate = false;
|
|
|
|
if (_placed)
|
|
{
|
|
if (_parentPivot != null)
|
|
_parentPivot.SetActive(true);
|
|
|
|
if (_parentCanvasGroup != null)
|
|
_parentCanvasGroup.alpha = 1f;
|
|
|
|
ApplyRotationImmediate(_currentRotationStep);
|
|
}
|
|
else
|
|
{
|
|
if (_parentPivot != null)
|
|
_parentPivot.SetActive(false);
|
|
|
|
if (_parentCanvasGroup != null)
|
|
_parentCanvasGroup.alpha = 0f;
|
|
}
|
|
|
|
RefreshVisualState();
|
|
}
|
|
|
|
public override async UniTask OnInteract(ItemDataSo item = null)
|
|
{
|
|
if (!IsInteractable())
|
|
return;
|
|
|
|
await RotateToNextStep();
|
|
await _clockFace.NotifyHandChanged();
|
|
}
|
|
|
|
public async UniTask Place()
|
|
{
|
|
if (_placed)
|
|
return;
|
|
|
|
_placed = true;
|
|
_locked = false;
|
|
_canRotate = false;
|
|
|
|
CancelPlaceTween();
|
|
|
|
_placeCTS = new CancellationTokenSource();
|
|
|
|
if (_randomiseRotationOnFirstPlace)
|
|
_currentRotationStep = Random.Range(0, _rotationSteps.Length);
|
|
|
|
if (_parentPivot != null)
|
|
_parentPivot.SetActive(true);
|
|
|
|
ApplyRotationImmediate(_currentRotationStep);
|
|
|
|
if (_parentCanvasGroup != null)
|
|
{
|
|
_parentCanvasGroup.alpha = 0f;
|
|
_parentCanvasGroup.blocksRaycasts = false;
|
|
_parentCanvasGroup.interactable = false;
|
|
}
|
|
|
|
_placeSequence.Stop();
|
|
_placeSequence = Sequence.Create()
|
|
.Group(Tween.Alpha(_parentCanvasGroup, 1f, _placeDuration, _placeEase));
|
|
|
|
try
|
|
{
|
|
await _placeSequence.ToUniTask(cancellationToken: _placeCTS.Token);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
RefreshVisualState();
|
|
}
|
|
|
|
public void RestoreState(bool placed, int rotationStep, bool locked)
|
|
{
|
|
CancelPlaceTween();
|
|
CancelRotateTween();
|
|
|
|
_placed = placed;
|
|
_locked = locked;
|
|
_isRotating = false;
|
|
_canRotate = false;
|
|
_currentRotationStep = Mathf.Clamp(rotationStep, 0, 11);
|
|
|
|
if (_parentPivot != null)
|
|
_parentPivot.SetActive(_placed);
|
|
|
|
if (_placed)
|
|
{
|
|
ApplyRotationImmediate(_currentRotationStep);
|
|
|
|
if (_parentCanvasGroup != null)
|
|
_parentCanvasGroup.alpha = 1f;
|
|
}
|
|
else
|
|
{
|
|
if (_parentCanvasGroup != null)
|
|
_parentCanvasGroup.alpha = 0f;
|
|
}
|
|
|
|
RefreshVisualState();
|
|
}
|
|
|
|
public void SetCanRotate(bool canRotate)
|
|
{
|
|
_canRotate = canRotate;
|
|
RefreshVisualState();
|
|
}
|
|
|
|
public void Lock()
|
|
{
|
|
_locked = true;
|
|
_canRotate = false;
|
|
RefreshVisualState();
|
|
}
|
|
|
|
public void Hide()
|
|
{
|
|
CancelPlaceTween();
|
|
CancelRotateTween();
|
|
|
|
_canRotate = false;
|
|
_isRotating = false;
|
|
|
|
if (_parentCanvasGroup != null)
|
|
{
|
|
_parentCanvasGroup.blocksRaycasts = false;
|
|
_parentCanvasGroup.interactable = false;
|
|
_parentCanvasGroup.alpha = 0f;
|
|
}
|
|
|
|
if (_parentPivot != null)
|
|
_parentPivot.SetActive(false);
|
|
}
|
|
|
|
private async UniTask RotateToNextStep()
|
|
{
|
|
if (!IsInteractable())
|
|
return;
|
|
|
|
_isRotating = true;
|
|
RefreshVisualState();
|
|
|
|
CancelRotateTween();
|
|
_rotateCTS = new CancellationTokenSource();
|
|
|
|
_currentRotationStep = (_currentRotationStep + 1) % 12;
|
|
|
|
Vector3 targetEuler = _parentPivot.transform.localEulerAngles;
|
|
targetEuler.z = _rotationSteps[_currentRotationStep];
|
|
|
|
_rotateSequence.Stop();
|
|
_rotateSequence = Sequence.Create()
|
|
.Group(
|
|
Tween.LocalRotation(
|
|
_parentPivot.transform,
|
|
Quaternion.Euler(targetEuler),
|
|
_rotateDuration,
|
|
_rotateEase));
|
|
|
|
try
|
|
{
|
|
await _rotateSequence.ToUniTask(cancellationToken: _rotateCTS.Token);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
_isRotating = false;
|
|
RefreshVisualState();
|
|
}
|
|
|
|
private void ApplyRotationImmediate(int step)
|
|
{
|
|
if (_parentPivot == null)
|
|
return;
|
|
|
|
Vector3 euler = _parentPivot.transform.localEulerAngles;
|
|
euler.z = _rotationSteps[Mathf.Clamp(step, 0, 11)];
|
|
_parentPivot.transform.localEulerAngles = euler;
|
|
}
|
|
|
|
private void RefreshVisualState()
|
|
{
|
|
bool interactable = IsInteractable();
|
|
|
|
if (_parentCanvasGroup != null)
|
|
{
|
|
_parentCanvasGroup.blocksRaycasts = interactable;
|
|
_parentCanvasGroup.interactable = interactable;
|
|
}
|
|
}
|
|
|
|
private bool IsInteractable()
|
|
{
|
|
return _placed && !_locked && !_isRotating && _canRotate;
|
|
}
|
|
|
|
private void CancelPlaceTween()
|
|
{
|
|
_placeSequence.Stop();
|
|
|
|
if (_placeCTS != null)
|
|
{
|
|
_placeCTS.Cancel();
|
|
_placeCTS.Dispose();
|
|
_placeCTS = null;
|
|
}
|
|
}
|
|
|
|
private void CancelRotateTween()
|
|
{
|
|
_rotateSequence.Stop();
|
|
|
|
if (_rotateCTS != null)
|
|
{
|
|
_rotateCTS.Cancel();
|
|
_rotateCTS.Dispose();
|
|
_rotateCTS = null;
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
CancelPlaceTween();
|
|
CancelRotateTween();
|
|
}
|
|
}
|
|
} |