using System; using System.Collections; using UnityEngine; using UnityEngine.UI; using TMPro; public class StandByPanel : BasePanel { [Header("UI组件")] public Image CompanyLogoImage; // 公司图标 public Image LoadingProgressBar; // 加载进度条 public TextMeshProUGUI LoadingStatusText; // 加载状态文本 private CanvasGroup SplashCanvasGroup; // 启动界面Canvas Group用于淡入淡出 [Header("动画参数")] [SerializeField] private float LogoFadeInDuration = 0.5f; // 图标淡入时间 [SerializeField] private float MinSplashDuration = 3f; // 最小启动界面显示时间(秒) [SerializeField] private float ConnectionTimeOut = 10f; // 连接超时时间(秒) [SerializeField] private float FadeOutDuration = 0.5f; // 淡出时间 [Header("串口配置")] [SerializeField] private string WindowsPortName = "COM1"; // Windows 默认串口名 [SerializeField] private string AndroidPortPath = "/dev/ttyS4"; // 安卓默认设备路径(示例) [SerializeField] private int DefaultBaudRate = 115200; // 默认波特率 private SerialCommunicationService _serialService; private DCSAlarmManager _alarmManager; private bool _isConnectionSuccessful = true; private bool _communicationErrorDetected = false; private DateTime _startTime; private const string COMMUNICATION_ERROR_TITLE = "通讯异常"; private const string COMMUNICATION_ERROR_MESSAGE = "设备通讯异常,请检查:\n1. 数据线连接是否正常\n2. 设备是否已开启\n3. 重启应用重新尝试\n\n无法进入应用。"; public override void Init() { // 获取服务 _serialService = ServiceLocator.Get() as SerialCommunicationService; _alarmManager = DCSAlarmManager.Instance; InitializeUI(); _startTime = DateTime.Now; StartCoroutine(InitializationSequence()); } private void InitializeUI() { // 确保Canvas Group存在 if (SplashCanvasGroup == null) { SplashCanvasGroup = GetComponent(); if (SplashCanvasGroup == null) { SplashCanvasGroup = gameObject.AddComponent(); } } // 初始化进度条 if (LoadingProgressBar != null) { LoadingProgressBar.fillAmount = 0f; } // 初始化文本 if (LoadingStatusText != null) { LoadingStatusText.text = "初始化中..."; } } /// /// 启动序列:动画 -> 连接 -> 验证 -> 进入界面 /// private IEnumerator InitializationSequence() { // Step 1: 淡入公司图标 yield return StartCoroutine(FadeInLogo()); // Step 2: 在动画期间进行串口连接 UpdateLoadingStatus("连接设备中...", 0.2f); yield return StartCoroutine(ConnectSerialPort()); // Step 3: 检查通讯状态 UpdateLoadingStatus("验证通讯中...", 0.5f); yield return StartCoroutine(VerifyCommunication()); // Step 4: 确保最小显示时间 float elapsedTime = (float)(DateTime.Now - _startTime).TotalSeconds; if (elapsedTime < MinSplashDuration) { UpdateLoadingStatus("准备就绪...", 0.8f); yield return new WaitForSeconds(MinSplashDuration - elapsedTime); } // Step 5: 根据连接结果处理 if (_communicationErrorDetected) { yield return StartCoroutine(ShowCommunicationErrorDialog()); } else { UpdateLoadingStatus("进入应用...", 1f); yield return StartCoroutine(FadeOutAndEnterApp()); } } /// /// 淡入公司图标 /// private IEnumerator FadeInLogo() { if (CompanyLogoImage != null) { CompanyLogoImage.color = new Color(1, 1, 1, 0); float elapsedTime = 0f; while (elapsedTime < LogoFadeInDuration) { elapsedTime += Time.deltaTime; float alpha = Mathf.Clamp01(elapsedTime / LogoFadeInDuration); CompanyLogoImage.color = new Color(1, 1, 1, alpha); yield return null; } CompanyLogoImage.color = new Color(1, 1, 1, 1); } yield return new WaitForSeconds(0.5f); } /// /// 连接串口 /// private IEnumerator ConnectSerialPort() { if (_serialService == null) { Debug.LogError("[SplashScreen] SerialCommunicationService not found!"); _isConnectionSuccessful = false; yield break; } // 订阅通讯错误事件 _serialService.OnCommunicationError -= OnSerialCommunicationError; _serialService.OnCommunicationError += OnSerialCommunicationError; // 尝试连接 float connectionStartTime = Time.time; // 根据平台选择串口名/设备路径 string portName = GetPortNameForPlatform(); UpdateLoadingStatus($"正在连接: {portName} @ {DefaultBaudRate}", 0.25f); Debug.Log($"[SplashScreen] 尝试连接串口: {portName} @ {DefaultBaudRate}"); bool connected = _serialService.Connect(portName, DefaultBaudRate); if (!connected) { Debug.LogWarning("[SplashScreen] Failed to connect serial port"); _isConnectionSuccessful = false; _communicationErrorDetected = true; yield break; } // Debug.Log("[SplashScreen] Serial port connected, waiting for handshake..."); // _serialService.SendHandshakeRequest(); // // 等待握手完成或超时 // float timeoutTime = Time.time + ConnectionTimeOut; // while (!_serialService.IsHandshakeCompleted && Time.time < timeoutTime) // { // yield return new WaitForSeconds(0.1f); // } // if (!_serialService.IsHandshakeCompleted) // { // Debug.LogWarning("[SplashScreen] Serial handshake timeout!"); // _communicationErrorDetected = true; // } // else // { // Debug.Log("[SplashScreen] Serial handshake completed successfully!"); // } } /// /// 返回当前平台的串口名/设备路径 /// 注意:安卓端通常为 /dev/ttyS* 或 /dev/ttyUSB* /// 实际设备路径应根据硬件与驱动调整,可通过日志或配置下发 /// private string GetPortNameForPlatform() { #if UNITY_ANDROID && !UNITY_EDITOR return string.IsNullOrEmpty(AndroidPortPath) ? "/dev/ttyS4" : AndroidPortPath; #else return string.IsNullOrEmpty(WindowsPortName) ? "COM1" : WindowsPortName; #endif } /// /// 验证通讯状态 /// private IEnumerator VerifyCommunication() { // 等待一段时间,让心跳报告处理完成 yield return new WaitForSeconds(1f); // 检查DCSAlarmManager是否在启动阶段检测到通讯异常 if (_alarmManager != null && _alarmManager.HasCommunicationErrorDuringStartup) { Debug.LogError("[SplashScreen] Communication error detected by DCSAlarmManager!"); _communicationErrorDetected = true; } // 如果未检测到通讯错误,则认为通讯正常 if (!_communicationErrorDetected) { Debug.Log("[SplashScreen] Communication verification passed!"); } } /// /// 显示通讯异常对话框 /// private IEnumerator ShowCommunicationErrorDialog() { // 淡出启动界面 yield return StartCoroutine(FadeOut()); // 显示错误对话框 bool dialogClosed = false; ConfirmDialog.Show( COMMUNICATION_ERROR_TITLE, COMMUNICATION_ERROR_MESSAGE, onConfirm: () => { dialogClosed = true; // 关闭应用 #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #else Application.Quit(); #endif }, onCancel: null, confirmText: "关闭应用", cancelText: "", isWarning: true, showCancelButton: false ); // 等待用户关闭对话框 while (!dialogClosed) { yield return new WaitForSeconds(0.1f); } } /// /// 淡出并进入应用 /// private IEnumerator FadeOutAndEnterApp() { yield return StartCoroutine(FadeOut()); // 进入登录界面 UIManager.Instance.ShowPanel(); // 销毁启动界面 Destroy(gameObject); } /// /// 淡出启动界面 /// private IEnumerator FadeOut() { if (SplashCanvasGroup == null) yield break; float elapsedTime = 0f; while (elapsedTime < FadeOutDuration) { elapsedTime += Time.deltaTime; SplashCanvasGroup.alpha = Mathf.Lerp(1f, 0f, elapsedTime / FadeOutDuration); yield return null; } SplashCanvasGroup.alpha = 0f; } /// /// 更新加载状态文本和进度条 /// private void UpdateLoadingStatus(string statusText, float progress) { if (LoadingStatusText != null) { LoadingStatusText.text = statusText; } if (LoadingProgressBar != null) { LoadingProgressBar.fillAmount = Mathf.Clamp01(progress); } } /// /// 处理通讯错误事件 /// private void OnSerialCommunicationError() { Debug.LogWarning("[SplashScreen] Serial communication error detected!"); _communicationErrorDetected = true; } void OnDestroy() { // 取消订阅 if (_serialService != null) { _serialService.OnCommunicationError -= OnSerialCommunicationError; } } public void GenerateLoginUI() { // 生成登录界面的逻辑 UIManager.Instance.ShowPanel(); } }