182 lines
5.7 KiB
C#
182 lines
5.7 KiB
C#
using System;
|
|
using JetBrains.Annotations;
|
|
using SharpUI.Source.Common.UI.Util.TimeUtils;
|
|
using SharpUI.Source.Common.Util.Extensions;
|
|
using TMPro;
|
|
using UniRx;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace SharpUI.Source.Common.UI.Elements.SkillBars
|
|
{
|
|
public class SkillBar : MonoBehaviour
|
|
{
|
|
public enum CooldownConsumeType { Fill, Drain }
|
|
|
|
private const float SkillBarMargin = 2f;
|
|
private const string DefaultBarTextFormat = "{0:0.0} sec";
|
|
|
|
[SerializeField] public Image skillBarImage;
|
|
[SerializeField] public Image skillIconImage;
|
|
[SerializeField] public TMP_Text skillNameText;
|
|
[SerializeField] public TMP_Text skillRemainingCooldownText;
|
|
[SerializeField] public float skillCooldown;
|
|
[SerializeField] public float skillCooldownRemaining;
|
|
[SerializeField] public string skillName;
|
|
[SerializeField] public CooldownConsumeType consumeType = CooldownConsumeType.Fill;
|
|
[SerializeField] public bool depleteWhenCompleted;
|
|
|
|
[CanBeNull] private Subject<Unit> _castFinishedObserver = new Subject<Unit>();
|
|
private float _cooldownRemaining;
|
|
private float _cooldown;
|
|
private bool _isFinished;
|
|
private bool _isCoolingDown;
|
|
private RectTransform _rectTransform;
|
|
private RectTransform _skillBarImageTransform;
|
|
private ITimeProvider _timeProvider = new TimeProvider();
|
|
[CanBeNull] private ManagedUiUpdate _managedUiUpdate;
|
|
|
|
public void Start()
|
|
{
|
|
InitUiUpdater();
|
|
InitDefaultValues();
|
|
UpdateProgress(0);
|
|
}
|
|
|
|
public void OnDestroy()
|
|
{
|
|
_managedUiUpdate?.StopUiUpdates();
|
|
}
|
|
|
|
public void Cancel()
|
|
{
|
|
Deplete();
|
|
}
|
|
|
|
public void SetTimeProvider(ITimeProvider timeProvider) => _timeProvider = timeProvider;
|
|
|
|
public void StartCooldown()
|
|
{
|
|
_isCoolingDown = true;
|
|
}
|
|
|
|
public void RestartCooldown()
|
|
{
|
|
InitDefaultValues();
|
|
StartCooldown();
|
|
}
|
|
|
|
private void InitUiUpdater()
|
|
{
|
|
_managedUiUpdate = new ManagedUiUpdate();
|
|
_managedUiUpdate.ObserveUiUpdate().SubscribeWith(this, UpdateProgress);
|
|
}
|
|
|
|
private void InitDefaultValues()
|
|
{
|
|
if (!IsValidSetup()) return;
|
|
|
|
_isFinished = false;
|
|
_cooldown = skillCooldown;
|
|
_cooldownRemaining = skillCooldownRemaining;
|
|
skillNameText.text = skillName;
|
|
_rectTransform = GetComponent<RectTransform>();
|
|
_skillBarImageTransform = skillBarImage.GetComponent<RectTransform>();
|
|
InitConsumeType();
|
|
SetRemainingCooldownText();
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (!_isCoolingDown) return;
|
|
|
|
var deltaTime = _timeProvider.GetDeltaTime();
|
|
_cooldownRemaining = Math.Max(0, _cooldownRemaining - deltaTime);
|
|
_managedUiUpdate?.ConsumeDeltaTime(deltaTime);
|
|
}
|
|
|
|
public IObservable<Unit> ObserveCooldownFinished() => _castFinishedObserver;
|
|
|
|
public bool IsFinished() => _isFinished;
|
|
|
|
public bool IsUpdatingUi() => _managedUiUpdate != null && !_managedUiUpdate.IsDepleted();
|
|
|
|
private void InitConsumeType()
|
|
{
|
|
var scale = consumeType == CooldownConsumeType.Drain ? -1 : 1;
|
|
skillBarImage.GetComponent<RectTransform>().localScale = new Vector3(scale, scale, 1);
|
|
}
|
|
|
|
private bool IsValidSetup()
|
|
{
|
|
return skillCooldownRemaining > skillCooldown
|
|
? throw new OverflowException("Remaining cooldown should not be larger than cooldown.")
|
|
: true;
|
|
}
|
|
|
|
public void UpdateProgress(float elapsedTime)
|
|
{
|
|
CheckStatus();
|
|
|
|
if (_isFinished || !_isCoolingDown) return;
|
|
|
|
SetRemainingCooldownText();
|
|
SetBarLength();
|
|
}
|
|
|
|
private void CheckStatus()
|
|
{
|
|
if (_cooldownRemaining <= 0 && !_isFinished)
|
|
SkillFinished();
|
|
}
|
|
|
|
private void SkillFinished()
|
|
{
|
|
_isFinished = true;
|
|
_isCoolingDown = false;
|
|
_castFinishedObserver?.OnNext(Unit.Default);
|
|
|
|
if (depleteWhenCompleted)
|
|
Deplete();
|
|
}
|
|
|
|
private void Deplete()
|
|
{
|
|
_castFinishedObserver = null;
|
|
DestroyImmediate(gameObject);
|
|
}
|
|
|
|
private void SetRemainingCooldownText()
|
|
{
|
|
skillRemainingCooldownText.text = string.Format(DefaultBarTextFormat, _cooldownRemaining);
|
|
}
|
|
|
|
private void SetBarLength()
|
|
{
|
|
if (consumeType == CooldownConsumeType.Fill)
|
|
FillBar();
|
|
else
|
|
DrainBar();
|
|
}
|
|
|
|
private void FillBar()
|
|
{
|
|
var progressPercentage = CurrentPercentage();
|
|
var barProgressWidth = GetBarWidth() * progressPercentage;
|
|
_skillBarImageTransform
|
|
.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, SkillBarMargin, barProgressWidth);
|
|
}
|
|
|
|
private void DrainBar()
|
|
{
|
|
var progressPercentage = 1f - CurrentPercentage();
|
|
var barProgressWidth = GetBarWidth() * progressPercentage;
|
|
_skillBarImageTransform
|
|
.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, SkillBarMargin, barProgressWidth);
|
|
}
|
|
|
|
private float CurrentPercentage() => (_cooldown - _cooldownRemaining) / _cooldown;
|
|
|
|
private float GetBarWidth() => _rectTransform.rect.size.x - SkillBarMargin * 2;
|
|
}
|
|
} |