Additional Levels added. Mostly just base artwork so far.
This commit is contained in:
@@ -1,7 +1,295 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using BriarQueen.Framework.Managers.Levels.Data;
|
||||
using BriarQueen.Framework.Managers.Player.Data;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using PrimeTween;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace BriarQueen.Game.Levels.ChapterOne.LaxleyHouse.FireplaceLockbox
|
||||
{
|
||||
public class LockboxSlot
|
||||
public class LockboxSlot : BaseItem
|
||||
{
|
||||
|
||||
private const int MinDigit = 1;
|
||||
private const int MaxDigit = 9;
|
||||
|
||||
[Header("Components")]
|
||||
[SerializeField]
|
||||
private Image _currentNumberImage;
|
||||
|
||||
[SerializeField]
|
||||
private Image _nextNumberImage;
|
||||
|
||||
[Header("Animation")]
|
||||
[SerializeField]
|
||||
private float _spinPadding = 8f;
|
||||
|
||||
[SerializeField]
|
||||
private float _spinDuration = 0.15f;
|
||||
|
||||
[SerializeField]
|
||||
private Ease _spinEase = Ease.OutCubic;
|
||||
|
||||
[SerializeField]
|
||||
[Range(0f, 1f)]
|
||||
private float _fadedAlpha = 0.4f;
|
||||
|
||||
private RectTransform _currentRect;
|
||||
private RectTransform _nextRect;
|
||||
|
||||
private Sequence _slotSequence;
|
||||
private CancellationTokenSource _slotCancellationTokenSource;
|
||||
|
||||
private Func<int, Sprite> _spriteResolver;
|
||||
private Action _onValueChanged;
|
||||
|
||||
public int CurrentValue { get; private set; } = MinDigit;
|
||||
|
||||
public void Initialize(Func<int, Sprite> spriteResolver, Action onValueChanged)
|
||||
{
|
||||
_spriteResolver = spriteResolver;
|
||||
_onValueChanged = onValueChanged;
|
||||
|
||||
_currentRect = _currentNumberImage != null ? _currentNumberImage.rectTransform : null;
|
||||
_nextRect = _nextNumberImage != null ? _nextNumberImage.rectTransform : null;
|
||||
|
||||
SyncHelperImageLayout();
|
||||
ApplyValueImmediate(CurrentValue);
|
||||
}
|
||||
|
||||
public void ApplyValueImmediate(int value)
|
||||
{
|
||||
CurrentValue = WrapValue(value);
|
||||
|
||||
CancelTweenIfRunning();
|
||||
SyncHelperImageLayout();
|
||||
|
||||
var sprite = ResolveSprite(CurrentValue);
|
||||
|
||||
if (_currentNumberImage != null)
|
||||
{
|
||||
_currentNumberImage.sprite = sprite;
|
||||
_currentNumberImage.enabled = sprite != null;
|
||||
_currentNumberImage.color = Color.white;
|
||||
}
|
||||
|
||||
if (_nextNumberImage != null)
|
||||
{
|
||||
_nextNumberImage.sprite = null;
|
||||
_nextNumberImage.enabled = false;
|
||||
_nextNumberImage.color = Color.white;
|
||||
}
|
||||
|
||||
if (_currentRect != null)
|
||||
_currentRect.anchoredPosition = Vector2.zero;
|
||||
|
||||
if (_nextRect != null)
|
||||
_nextRect.anchoredPosition = GetHiddenPosition();
|
||||
}
|
||||
|
||||
public override async UniTask OnInteract(ItemDataSo item = null)
|
||||
{
|
||||
if (item != null)
|
||||
return;
|
||||
|
||||
await SpinToNextValue();
|
||||
}
|
||||
|
||||
public async UniTask SpinToNextValue()
|
||||
{
|
||||
if (_currentNumberImage == null || _nextNumberImage == null || _currentRect == null || _nextRect == null)
|
||||
return;
|
||||
|
||||
int nextValue = WrapValue(CurrentValue + 1);
|
||||
var nextSprite = ResolveSprite(nextValue);
|
||||
|
||||
if (nextSprite == null)
|
||||
{
|
||||
Debug.LogWarning($"[LockboxSlot] Missing sprite for value {nextValue}.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
CancelTweenIfRunning();
|
||||
SyncHelperImageLayout();
|
||||
|
||||
_slotCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_nextNumberImage.sprite = nextSprite;
|
||||
_nextNumberImage.enabled = true;
|
||||
_nextNumberImage.color = new Color(1f, 1f, 1f, _fadedAlpha);
|
||||
|
||||
_currentNumberImage.enabled = true;
|
||||
_currentNumberImage.color = Color.white;
|
||||
|
||||
_currentRect.anchoredPosition = Vector2.zero;
|
||||
_nextRect.anchoredPosition = GetHiddenPosition();
|
||||
|
||||
_slotSequence = Sequence.Create(useUnscaledTime: true)
|
||||
.Group(Tween.UIAnchoredPosition(
|
||||
_currentRect,
|
||||
GetVisibleExitPosition(),
|
||||
_spinDuration,
|
||||
_spinEase,
|
||||
useUnscaledTime: true))
|
||||
.Group(Tween.UIAnchoredPosition(
|
||||
_nextRect,
|
||||
Vector2.zero,
|
||||
_spinDuration,
|
||||
_spinEase,
|
||||
useUnscaledTime: true))
|
||||
.Group(Tween.Alpha(
|
||||
_currentNumberImage,
|
||||
new TweenSettings<float>
|
||||
{
|
||||
endValue = _fadedAlpha,
|
||||
settings = new TweenSettings
|
||||
{
|
||||
duration = _spinDuration,
|
||||
useUnscaledTime = true
|
||||
}
|
||||
}))
|
||||
.Group(Tween.Alpha(
|
||||
_nextNumberImage,
|
||||
new TweenSettings<float>
|
||||
{
|
||||
endValue = 1f,
|
||||
settings = new TweenSettings
|
||||
{
|
||||
duration = _spinDuration,
|
||||
useUnscaledTime = true
|
||||
}
|
||||
}));
|
||||
|
||||
try
|
||||
{
|
||||
await _slotSequence.ToUniTask(cancellationToken: _slotCancellationTokenSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_slotSequence.isAlive)
|
||||
_slotSequence.Stop();
|
||||
|
||||
_slotSequence = default;
|
||||
|
||||
_slotCancellationTokenSource?.Dispose();
|
||||
_slotCancellationTokenSource = null;
|
||||
}
|
||||
|
||||
SwapImages();
|
||||
CurrentValue = nextValue;
|
||||
|
||||
PrepareHiddenImage();
|
||||
_onValueChanged?.Invoke();
|
||||
}
|
||||
|
||||
private Sprite ResolveSprite(int value)
|
||||
{
|
||||
return _spriteResolver?.Invoke(WrapValue(value));
|
||||
}
|
||||
|
||||
private int WrapValue(int value)
|
||||
{
|
||||
value %= MaxDigit;
|
||||
|
||||
if (value <= 0)
|
||||
value += MaxDigit;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private void SwapImages()
|
||||
{
|
||||
(_currentNumberImage, _nextNumberImage) = (_nextNumberImage, _currentNumberImage);
|
||||
(_currentRect, _nextRect) = (_nextRect, _currentRect);
|
||||
}
|
||||
|
||||
private void PrepareHiddenImage()
|
||||
{
|
||||
if (_currentNumberImage != null)
|
||||
{
|
||||
_currentNumberImage.enabled = true;
|
||||
_currentNumberImage.color = Color.white;
|
||||
}
|
||||
|
||||
if (_currentRect != null)
|
||||
_currentRect.anchoredPosition = Vector2.zero;
|
||||
|
||||
if (_nextNumberImage != null)
|
||||
{
|
||||
_nextNumberImage.sprite = null;
|
||||
_nextNumberImage.enabled = false;
|
||||
_nextNumberImage.color = Color.white;
|
||||
}
|
||||
|
||||
if (_nextRect != null)
|
||||
_nextRect.anchoredPosition = GetHiddenPosition();
|
||||
}
|
||||
|
||||
private void SyncHelperImageLayout()
|
||||
{
|
||||
if (_currentRect == null || _nextRect == null)
|
||||
return;
|
||||
|
||||
_nextRect.anchorMin = _currentRect.anchorMin;
|
||||
_nextRect.anchorMax = _currentRect.anchorMax;
|
||||
_nextRect.pivot = _currentRect.pivot;
|
||||
_nextRect.sizeDelta = _currentRect.sizeDelta;
|
||||
_nextRect.localScale = _currentRect.localScale;
|
||||
_nextRect.localRotation = _currentRect.localRotation;
|
||||
}
|
||||
|
||||
private Vector2 GetHiddenPosition()
|
||||
{
|
||||
float travelDistance = GetTravelDistance();
|
||||
return new Vector2(0f, -travelDistance);
|
||||
}
|
||||
|
||||
private Vector2 GetVisibleExitPosition()
|
||||
{
|
||||
float travelDistance = GetTravelDistance();
|
||||
return new Vector2(0f, travelDistance);
|
||||
}
|
||||
|
||||
private float GetTravelDistance()
|
||||
{
|
||||
if (_currentRect == null)
|
||||
return _spinPadding;
|
||||
|
||||
float rectHeight = _currentRect.rect.height;
|
||||
|
||||
if (rectHeight <= 0f && _currentNumberImage != null)
|
||||
rectHeight = _currentNumberImage.preferredHeight;
|
||||
|
||||
return rectHeight + _spinPadding;
|
||||
}
|
||||
|
||||
private void CancelTweenIfRunning()
|
||||
{
|
||||
if (_slotCancellationTokenSource != null && !_slotCancellationTokenSource.IsCancellationRequested)
|
||||
_slotCancellationTokenSource.Cancel();
|
||||
|
||||
if (_slotSequence.isAlive)
|
||||
_slotSequence.Stop();
|
||||
|
||||
_slotSequence = default;
|
||||
|
||||
_slotCancellationTokenSource?.Dispose();
|
||||
_slotCancellationTokenSource = null;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
CancelTweenIfRunning();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
CancelTweenIfRunning();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user