Laxley Grandfather Clock puzzle artwork done.
This commit is contained in:
@@ -1,7 +1,316 @@
|
||||
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
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user