Loading Done
This commit is contained in:
8
Assets/Darkmatter/Code/Features/Loading.meta
Normal file
8
Assets/Darkmatter/Code/Features/Loading.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09a530ea6231c44aeb08c880de69eeda
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Darkmatter/Code/Features/Loading/Docs.meta
Normal file
8
Assets/Darkmatter/Code/Features/Loading/Docs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b3ba9e51a74d4a0f8673b21a9124298
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
# Loading Feature
|
||||
|
||||
## Purpose
|
||||
- Owns the passive loading-screen presenter/view pair shared by boot and scene transitions.
|
||||
- Centralizes progress and status updates for the user-facing loading UI.
|
||||
|
||||
## Public Entry Points
|
||||
- `LoadingPresenter`
|
||||
- `LoadingScreenView`
|
||||
|
||||
## Dependencies
|
||||
- Consumed from App/loading orchestration via the loading contracts.
|
||||
- Should remain presentation-only and avoid feature-specific gameplay logic.
|
||||
|
||||
## Extension Notes
|
||||
- Add new UI affordances here only if they are generic to every loading flow.
|
||||
- Keep orchestration decisions in App/GameFlow/MainMenu sequences, not in the presenter or view.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14e78c2457d7941859fa8192ae052e72
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Features.Loading",
|
||||
"rootNamespace": "Darkmatter.Features.Loading",
|
||||
"references": [
|
||||
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
|
||||
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
|
||||
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:80ecb87cae9c44d19824e70ea7229748"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6b16414554114d0b971c01ee2f137fb
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
110
Assets/Darkmatter/Code/Features/Loading/LoadingPresenter.cs
Normal file
110
Assets/Darkmatter/Code/Features/Loading/LoadingPresenter.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Darkmatter.Core.Contracts.Features.Loading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Features.Loading
|
||||
{
|
||||
public class LoadingPresenter : ILoadingScreen
|
||||
{
|
||||
private const float SnapToCompleteThreshold = 0.9999f;
|
||||
private const float ProgressEpsilon = 0.0001f;
|
||||
|
||||
private readonly LoadingScreenView _view;
|
||||
private float _reportedProgress;
|
||||
private float _displayedProgress;
|
||||
private bool _isVisible;
|
||||
private bool _isAnimating;
|
||||
|
||||
public float CurrentProgress => _reportedProgress;
|
||||
|
||||
public LoadingPresenter(LoadingScreenView view)
|
||||
{
|
||||
_view = view;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
if (_isVisible)
|
||||
{
|
||||
_view.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
_reportedProgress = 0f;
|
||||
_displayedProgress = 0f;
|
||||
_view.SetProgress(0f);
|
||||
_view.Show();
|
||||
_isVisible = true;
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
if (_reportedProgress >= SnapToCompleteThreshold)
|
||||
{
|
||||
SnapDisplayedProgress(1f);
|
||||
}
|
||||
|
||||
_isVisible = false;
|
||||
_view.Hide();
|
||||
}
|
||||
|
||||
public void SetProgress(float progress)
|
||||
{
|
||||
progress = Mathf.Clamp01(progress);
|
||||
progress = Mathf.Max(_reportedProgress, progress);
|
||||
|
||||
if (progress >= SnapToCompleteThreshold)
|
||||
{
|
||||
_reportedProgress = 1f;
|
||||
SnapDisplayedProgress(1f);
|
||||
return;
|
||||
}
|
||||
|
||||
_reportedProgress = progress;
|
||||
if (!_isVisible)
|
||||
{
|
||||
SnapDisplayedProgress(progress);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_displayedProgress + ProgressEpsilon >= _reportedProgress || _isAnimating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AnimateProgressAsync().Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid AnimateProgressAsync()
|
||||
{
|
||||
_isAnimating = true;
|
||||
try
|
||||
{
|
||||
while (_isVisible && _displayedProgress + ProgressEpsilon < _reportedProgress)
|
||||
{
|
||||
var deltaTime = Mathf.Max(Time.unscaledDeltaTime, 1f / 60f);
|
||||
var smoothing = 1f - Mathf.Exp(-_view.LoadingSmoothTime * deltaTime);
|
||||
_displayedProgress = Mathf.Lerp(_displayedProgress, _reportedProgress, smoothing);
|
||||
|
||||
if (_reportedProgress - _displayedProgress <= 0.001f)
|
||||
{
|
||||
_displayedProgress = _reportedProgress;
|
||||
}
|
||||
|
||||
_view.SetProgress(_displayedProgress);
|
||||
await UniTask.Yield(PlayerLoopTiming.Update);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isAnimating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SnapDisplayedProgress(float progress)
|
||||
{
|
||||
_displayedProgress = progress;
|
||||
_view.SetProgress(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00b0a1507e1d4b27b44e77c4967aed99
|
||||
timeCreated: 1771494975
|
||||
85
Assets/Darkmatter/Code/Features/Loading/LoadingScreenView.cs
Normal file
85
Assets/Darkmatter/Code/Features/Loading/LoadingScreenView.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using PrimeTween;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Darkmatter.Features.Loading
|
||||
{
|
||||
public class LoadingScreenView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Slider loadingSlider;
|
||||
[SerializeField] private TMP_Text statusText;
|
||||
[SerializeField] private float loadingSmoothTime = 10f;
|
||||
[SerializeField] private float messageHoldDuration = 2f;
|
||||
[SerializeField] private float messageFadeDuration = 0.4f;
|
||||
public float LoadingSmoothTime => loadingSmoothTime;
|
||||
|
||||
private static readonly string[] StatusLines = {
|
||||
"Blue is arguing with red...",
|
||||
"The crayons are dancing...",
|
||||
"Yellow spilled everywhere...",
|
||||
"Chasing escaped paint drops...",
|
||||
"Untying rainbow knots...",
|
||||
"Cleaning glitter explosions...",
|
||||
"The color monsters are hungry...",
|
||||
"Mixing mystery colors...",
|
||||
"Someone ate the purple paint...",
|
||||
"Teaching green to behave..."
|
||||
};
|
||||
|
||||
private Sequence _statusSequence;
|
||||
private int _statusIndex;
|
||||
|
||||
public void Show()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
StartStatusCycle();
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
StopStatusCycle();
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void SetProgress(float progress)
|
||||
{
|
||||
if (loadingSlider != null) loadingSlider.value = progress;
|
||||
}
|
||||
|
||||
private void StartStatusCycle()
|
||||
{
|
||||
if (statusText == null || StatusLines.Length == 0) return;
|
||||
|
||||
StopStatusCycle();
|
||||
|
||||
_statusIndex = Random.Range(0, StatusLines.Length);
|
||||
statusText.text = StatusLines[_statusIndex];
|
||||
statusText.alpha = 0f;
|
||||
|
||||
_statusSequence = Sequence.Create(useUnscaledTime: true, cycles: -1)
|
||||
.Chain(Tween.Alpha(statusText, 1f, messageFadeDuration, Ease.OutQuad))
|
||||
.ChainDelay(messageHoldDuration)
|
||||
.Chain(Tween.Alpha(statusText, 0f, messageFadeDuration, Ease.InQuad))
|
||||
.ChainCallback(AdvanceStatusLine);
|
||||
}
|
||||
|
||||
private void StopStatusCycle()
|
||||
{
|
||||
if (_statusSequence.isAlive) _statusSequence.Stop();
|
||||
_statusSequence = default;
|
||||
}
|
||||
|
||||
private void AdvanceStatusLine()
|
||||
{
|
||||
if (statusText == null) return;
|
||||
_statusIndex = (_statusIndex + 1) % StatusLines.Length;
|
||||
statusText.text = StatusLines[_statusIndex];
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
StopStatusCycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48d729b720c548e685793cc0348ae1c5
|
||||
timeCreated: 1771494930
|
||||
Reference in New Issue
Block a user