Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Base/Launcher.cs

320 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// C#
using Managers; // 确保日志命名空间正确
using System.Collections;
using System.Collections.Generic; // 新增用于List
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Base
{
// 请确保你在Unity Editor中将 'projectile' 的Inspector引用从 Gradient 更改为 CustomProgressBar
// 或者替换为你实际的进度条组件类型。
// 如果你没有 CustomProgressBar而想用 Image 或者别的,这些 Progress/Opacity 属性需要大幅修改。
public class Launcher : MonoBehaviour
{
public GameObject loadingUI;
// 假设 CustomProgressBar 是一个自定义组件,其 API 与原代码使用方式一致
// 如果这里是 UnityEngine.UI.Image需要完全改变 Progress 和 Opacity 的实现
public Gradient progressBar; // 自定义进度条组件
public TMP_Text describeText; // 描述文本
public float duration = 0.5f; // 每个步骤的过渡时间
public float fadeDuration = 2f; // 不透明度渐隐的时间
private float _currentProgressValue = 0f; // 实际的当前进度值0-1
private Color _initialTextColor; // 原始文本颜色,用于渐隐
private Color _initialProgressBarColor1; // 原始进度条颜色1
private Color _initialProgressBarColor2; // 原始进度条颜色2
// 存储所有需要加载和清理的管理器
private List<ILaunchManager> _managersToLoad;
// Progress 属性,更新进度条和颜色
public float Progress
{
set
{
// 确保进度值在0到1之间提高健壮性
_currentProgressValue = Mathf.Clamp01(value);
if (progressBar)
{
// 根据进度值平滑改变进度条的颜色
if (_currentProgressValue < 0.5f)
{
// 前半段color2 从初始色渐变到白色
progressBar.color2 = Color.Lerp(_initialProgressBarColor2, Color.white, _currentProgressValue * 2);
}
else
{
// 后半段color2 保持白色color1 从初始色渐变到白色
progressBar.color2 = Color.white;
progressBar.color1 = Color.Lerp(_initialProgressBarColor1, Color.white, (_currentProgressValue - 0.5f) * 2);
}
progressBar.Refresh(); // 通知自定义进度条组件更新显示
}
}
get => _currentProgressValue;
}
// Opacity 属性,更新 UI 元素的透明度
public float Opacity
{
set
{
var alpha = Mathf.Clamp01(value); // 确保透明度值在0到1之间
if (progressBar)
{
// 更新进度条颜色的透明度
Color c1 = progressBar.color1;
c1.a = alpha;
progressBar.color1 = c1;
Color c2 = progressBar.color2;
c2.a = alpha;
progressBar.color2 = c2;
progressBar.Refresh();
}
if (describeText)
{
// 更新描述文本颜色的透明度
// 渐隐时,描述文本的透明度在 Opacity > 0.5f 时才开始渐变可见
var textAlpha = alpha > 0.5f ? Mathf.Lerp(0f, _initialTextColor.a, (alpha - 0.5f) * 2) : 0f;
describeText.color = new Color(_initialTextColor.r, _initialTextColor.g, _initialTextColor.b, textAlpha);
}
}
}
private void Awake()
{
// 在 Awake 中初始化管理器列表并注册,确保在 Start 之前完成
_managersToLoad = new List<ILaunchManager>
{
Logging.UnityLogger.Instance, // UnityLogger的包装器
Managers.DefineManager.Instance,
Managers.PackagesImageManager.Instance,
Managers.TileManager.Instance,
Managers.AffiliationManager.Instance,
Managers.ItemResourceManager.Instance
// 当未来有新的管理器时,只需在这里添加 Managers.NewManager.Instance
};
// 缓存UI的初始颜色以便后续操作或重置
if (describeText != null)
{
_initialTextColor = describeText.color;
}
if (progressBar != null)
{
_initialProgressBarColor1 = progressBar.color1;
_initialProgressBarColor2 = progressBar.color2;
}
else
{
Debug.LogWarning("CustomProgressBar component not assigned to Launcher. Progress bar display may not work.");
}
}
private void Start()
{
// 如果 Program.Instance.needLoad 为 true表示需要完整的重新加载流程
// 否则如果不需要加载直接禁用UI并返回
if (!Program.Instance.needLoad)
{
loadingUI.SetActive(false);
return;
}
// 根据 Program.Instance.needLoad 的含义(需要重载),
// 在开始新的加载流程之前,先清理所有可能存在的旧管理器状态。
// 这确保了每次需要加载时,系统都处于一个干净的初始状态。
ClearAllManagers(); // <--- 关键修改在Load()之前调用ClearAllManagers()
// 初始化设置
Base.Setting.Instance.Init();
#if !DEBUG
// 在非DEBUG模式下从设置中获取过渡时间
duration = Base.Setting.Instance.CurrentSettings.progressStepDuration;
fadeDuration = Base.Setting.Instance.CurrentSettings.exitAnimationDuration;
#endif
Load(); // 启动加载流程内部会调用LoadAllManagers
Program.Instance.needLoad = false; // 加载完成后重置标志
}
/// <summary>
/// 启动游戏的加载流程。
/// </summary>
public void Load()
{
loadingUI.SetActive(true); // 激活加载UI
Progress = 0f; // 重置进度
Opacity = 1f; // 重置透明度为完全不透明
StartCoroutine(LoadAllManagers());
}
/// <summary>
/// 清理所有管理器,然后重新加载。用于游戏重载或场景切换后需要重新初始化所有数据的情况。
/// </summary>
public void Reload()
{
Debug.Log("<color=yellow>Performing a full reload of all managers...</color>");
StopAllCoroutines(); // 停止当前所有正在运行的加载协程,避免冲突
ClearAllManagers(); // 清理所有管理器
Load(); // 重新加载游戏数据
}
/// <summary>
/// 遍历所有已注册的管理器并调用它们的 Clear 方法。
/// </summary>
private void ClearAllManagers()
{
foreach (var manager in _managersToLoad)
{
try
{
manager.Clear();
}
catch (System.Exception ex)
{
Debug.LogError($"<color=red>Error clearing manager {manager.StepDescription}:</color> {ex.Message}\n{ex.StackTrace}");
}
}
}
/// <summary>
/// 协程:按顺序加载所有管理器。
/// </summary>
private IEnumerator LoadAllManagers()
{
for (var i = 0; i < _managersToLoad.Count; i++)
{
var manager = _managersToLoad[i];
// 更新描述文本,从管理器实例中获取
if (describeText != null)
{
describeText.text = manager.StepDescription;
}
// 计算当前阶段的目标进度
var targetProgress = (float)(i + 1) / _managersToLoad.Count;
// 平滑过渡进度条到下一个目标进度
yield return SmoothTransitionTo(targetProgress);
// 初始化对应的管理器,并进行异常处理
yield return InitializeManagerSafely(manager);
// 模拟耗时如果管理器Init方法本身很快可以 uncomment
// yield return new WaitForSeconds(0.1f);
}
// 所有管理器加载完成后的处理
if (describeText != null)
{
describeText.text = "加载完成!";
}
Progress = 1f; // 确保进度条最终达到100%
// 开始渐隐效果
yield return FadeOutProgressBar();
// 所有加载和动画结束后可以考虑卸载加载UI或跳转到主场景
// ToScene("MainGameScene"); // 如果有需要,在这里跳转到主游戏场景
}
/// <summary>
/// 尝试安全地初始化单个管理器,并捕获任何异常。
/// </summary>
/// <param name="manager">要初始化的管理器实例。</param>
private IEnumerator InitializeManagerSafely(ILaunchManager manager)
{
var initSuccess = false;
System.Exception initException = null;
try
{
manager.Init(); // 调用管理器的 Init 方法
initSuccess = true;
}
catch (System.Exception ex)
{
initException = ex; // 捕获异常
}
if (!initSuccess && initException != null)
{
// 记录错误日志
Debug.LogError($"<color=red>初始化管理器 '{manager.StepDescription}' 时出错:</color> {initException.Message}\n{initException.StackTrace}");
if (describeText != null)
{
describeText.text = $"{manager.StepDescription} (初始化失败)";
}
// 这里可以添加更复杂的错误处理,例如显示错误弹窗,或者重试逻辑
// yield break; // 如果错误严重,可以选择停止后续加载
}
yield return null; // 确保协程继续执行,即使没有做任何事
}
/// <summary>
/// 协程:平滑过渡进度条到指定的目标进度。
/// </summary>
/// <param name="targetProgress">目标进度值 (0-1)。</param>
private IEnumerator SmoothTransitionTo(float targetProgress)
{
var startProgress = _currentProgressValue; // 获取当前进度作为起始点
var elapsedTime = 0f;
while (elapsedTime < duration)
{
elapsedTime += Time.deltaTime;
// 使用 SmoothStep 实现更自然的加速和减速过渡效果
var t = Mathf.SmoothStep(0f, 1f, elapsedTime / duration);
Progress = Mathf.Lerp(startProgress, targetProgress, t);
yield return null;
}
Progress = targetProgress; // 确保最终进度精确达到目标值
}
/// <summary>
/// 协程渐隐加载UI的透明度。
/// </summary>
private IEnumerator FadeOutProgressBar()
{
var elapsedTime = 0f;
while (elapsedTime < fadeDuration)
{
elapsedTime += Time.deltaTime;
// 使用 SmoothStep 实现平滑渐隐
var t = Mathf.SmoothStep(0f, 1f, elapsedTime / fadeDuration);
Opacity = 1f - t; // 透明度从 1 线性渐变到 0
yield return null;
}
Opacity = 0f; // 确保最终不透明度为 0
loadingUI.SetActive(false); // 完全隐藏加载UI
}
/// <summary>
/// 静态方法:加载指定名称的场景。
/// </summary>
/// <param name="scene">要加载的场景名称。</param>
public static void ToScene(string scene)
{
SceneManager.LoadScene(scene);
}
}
}