Uipath 计时器倒计时弹窗

博客介绍了Uipath计时器倒计时弹窗应用案例,在Uipath运行过程将计时可视化,在循环中加入计时环节。还提及流程设计相关内容,如TimeA等变量类型,Auto Close message box需下载安装,且总时间与单次计时时间成整数倍。

Uipath 计时器倒计时弹窗

应用案例:
Uipath 运行过程将计时可视化,在循环中加入计时环节
在这里插入图片描述流程设计:

解析:

  1. TimeA,TimeB,TimeC 的变量类型是system-Timespan
  2. Auto Close message box需要进package里面取下载安装
  3. 注意总时间与单次计时时间成整数倍(此例是20秒与2秒)
    针对如上若有疑问或者更好的想法,欢迎大家留言讨论哦。
我会给出我的项目代码,你看着办往那个地方填:using System; public class 地块临时信息 { public 地块Data 地块; public string 开场白; public override string ToString() { return $"{地块}\n开场白: {开场白}"; } } using System; using System.Collections.Generic; using UnityEngine; // ScriptableObject 类,用于在 Unity 编辑器中创建 .asset 文件 [CreateAssetMenu(fileName = "新地块数据库", menuName = "地图/地块数据库", order = 1)] [Serializable] public class 地块数据库 : ScriptableObject { // 存储所有地块数据的列表 public List<地块Data> 地块列表 = new List<地块Data>(); // 添加一个地块数据 public void 添加地块(地块Data 地块) { 地块列表.Add(地块); Debug.Log($"✅ 添加地块 ({地块.X}, {地块.Y}) - {地块.生态类型}"); } // 查找指定坐标的地块 public 地块Data 查找地块(int x, int y) { return 地块列表.Find(地块 => 地块.X == x && 地块.Y == y); } // 判断某个坐标是否已存在地块 public bool 是否存在(int x, int y) { return 地块列表.Exists(地块 => 地块.X == x && 地块.Y == y); } // 保存数据库为 JSON 文件到持久化路径 public void 保存为JSON(string 文件名) { string json = JsonUtility.ToJson(new 地块数据库Wrapper { 数据 = 地块列表 }, true); string path = Application.persistentDataPath + "/" + 文件名 + ".json"; System.IO.File.WriteAllText(path, json); Debug.Log("✅ 地块数据已保存到: " + path); } // 从 JSON 文件加载数据到数据库 public void 从JSON加载(string 文件名) { string path = Application.persistentDataPath + "/" + 文件名 + ".json"; if (System.IO.File.Exists(path)) { string json = System.IO.File.ReadAllText(path); var wrapper = JsonUtility.FromJson<地块数据库Wrapper>(json); 地块列表 = wrapper.数据; Debug.Log("✅ 地块数据已从文件加载: " + path); } else { Debug.LogWarning("⚠️ 文件不存在: " + path); } } } // 包装类,用于支持 List 的 JSON 序列化 [Serializable] public class 地块数据库Wrapper { public List<地块Data> 数据; } using System; using UnityEngine; using System.Collections.Generic; [Serializable] public class 地块Data { public int X; public int Y; public string 生态类型; public List<string> 生物列表 = new List<string>(); public string 描述; public int 序号; public override string ToString() { return $"({X}, {Y}) - {生态类型}\n生物: {string.Join(", ", 生物列表)}\n描述: {描述}\n序号: {序号}"; } } using UnityEngine; using System.Collections; public class 聊天邀请管理器 : MonoBehaviour { // 单例模式 public static 聊天邀请管理器 Instance { get; private set; } [Header("引用")] public 聊天邀请弹窗 邀请弹窗; public 聊天系统 聊天系统; public bool 初始处于外出模式 = false; // 默认不进入外出模式 [Header("邀请设置")] public float 最小邀请间隔 = 10000f; public float 最大邀请间隔 = 30000f; public bool 调试模式 = true; private bool 处于外出模式 = false; private bool 正在聊天 = false; private Coroutine 邀请协程; private void Awake() { // 单例初始化 if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); // 可选:跨场景保持 } else { Destroy(gameObject); return; } } public void 设置正在聊天(bool 聊天中) { 正在聊天 = 聊天中; if (调试模式) Debug.Log($"聊天状态变更为: {聊天中}"); if (聊天中) { if (邀请协程 != null) { StopCoroutine(邀请协程); 邀请协程 = null; } } else if (处于外出模式 && 邀请协程 == null) { 邀请协程 = StartCoroutine(等待并邀请()); } } void Start() { // 验证引用 if (邀请弹窗 == null) Debug.LogError("聊天邀请管理器:请赋值邀请弹窗!"); else Debug.Log("聊天邀请管理器:已正确引用邀请弹窗"); // 自动查找聊天系统 if (聊天系统 == null) { 聊天系统 = FindObjectOfType<聊天系统>(); if (聊天系统 == null) Debug.LogError("聊天邀请管理器:未找到聊天系统组件!"); } // 初始状态设置 处于外出模式 = 初始处于外出模式; if (处于外出模式 && !正在聊天 && 邀请协程 == null) { 邀请协程 = StartCoroutine(等待并邀请()); } } // 显示邀请 public void 显示邀请(string 开场白, System.Action 接受回调) { if (邀请弹窗 == null) { Debug.LogError("邀请弹窗未赋值,无法显示邀请"); return; } 邀请弹窗.显示弹窗( "系统消息", // 标题 开场白, // 内容(开场白) 接受回调, // 接受回调 () => // 拒绝回调 { if (调试模式) Debug.Log("邀请被拒绝"); if (处于外出模式 && !正在聊天 && 邀请协程 == null) { 邀请协程 = StartCoroutine(等待并邀请()); } } ); } // 设置外出模式 public void 设置外出模式(bool 开启) { 处于外出模式 = 开启; if (调试模式) Debug.Log($"外出模式已{(开启 ? "开启" : "关闭")}"); if (开启 && !正在聊天 && 邀请协程 == null) { 邀请协程 = StartCoroutine(等待并邀请()); } else if (!开启 && 邀请协程 != null) { StopCoroutine(邀请协程); 邀请协程 = null; } } // 等待一段时间后显示邀请 private IEnumerator 等待并邀请() { while (true) { // 随机等待时间 float 等待时间 = Random.Range(最小邀请间隔, 最大邀请间隔); if (调试模式) Debug.Log($"将在 {等待时间:F1} 秒后显示下一次邀请"); yield return new WaitForSeconds(等待时间); // 检查是否仍需要显示邀请 if (处于外出模式 && !正在聊天) { 显示邀请("默认开场白", () => { if (聊天系统 != null) { 聊天系统.打开聊天窗口(); } }); break; // 显示后退出协程,等待聊天结束后重新开始 } else if (!处于外出模式 || 正在聊天) { break; } } 邀请协程 = null; } } using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using DG.Tweening; using System; using System.Collections; using System.Collections.Generic; public class 聊天邀请弹窗 : MonoBehaviour { [Header("UI元素")] public GameObject 邀请窗口; // 弹窗根对象 public Button 接受按钮; public Button 拒绝按钮; public CanvasGroup 弹窗画布组; public Text 标题文本; public Text 内容文本; public Text 倒计时文本; public GameObject 聊天框; [Header("配置")] public float 超时时间 = 30f; public float 动画时长 = 0.3f; public float 按钮缩放比例 = 1.05f; public string 默认标题 = "新的聊天邀请"; public string 默认内容 = "有人想与你聊天,是否接受?"; // 状态与队列管理 private bool 正在显示 = false; private Coroutine 倒计时协程; private Action 接受回调; private Action 拒绝回调; private Queue<弹窗数据> 弹窗队列 = new Queue<弹窗数据>(); // 弹窗数据结构 private struct 弹窗数据 { public string 标题; public string 内容; public Action 接受回调; public Action 拒绝回调; } void Awake() { // 确保对象激活(防止初始状态错误) if (!gameObject.activeSelf) gameObject.SetActive(true); // 初始化UI状态(只隐藏视觉效果,保持对象激活) 初始化UI状态(); // 检查并修复UI组件 检查并修复UI组件(); // 绑定按钮事件 绑定按钮事件(); } // 初始化UI状态(关键:保持对象激活) private void 初始化UI状态() { if (邀请窗口 != null && !邀请窗口.activeSelf) 邀请窗口.SetActive(true); if (弹窗画布组 != null) { 弹窗画布组.alpha = 0; 弹窗画布组.interactable = false; 弹窗画布组.blocksRaycasts = false; } 正在显示 = false; } // 检查并修复必要的UI组件 private void 检查并修复UI组件() { // 检查弹窗根对象 if (邀请窗口 == null) { Debug.LogError("聊天邀请弹窗:请赋值邀请窗口对象!"); return; } // 检查CanvasGroup if (弹窗画布组 == null) { 弹窗画布组 = 邀请窗口.GetComponent<CanvasGroup>(); if (弹窗画布组 == null) { 弹窗画布组 = 邀请窗口.AddComponent<CanvasGroup>(); Debug.LogWarning("聊天邀请弹窗:自动添加了CanvasGroup组件"); } } // 检查并修复按钮 修复按钮(接受按钮, "接受按钮"); 修复按钮(拒绝按钮, "拒绝按钮"); // 检查聊天框引用 if (聊天框 == null) Debug.LogError("聊天邀请弹窗:请赋值聊天框对象!"); } // 修复单个按钮(确保可交互) private void 修复按钮(Button 按钮, string 按钮名称) { if (按钮 == null) { Debug.LogError($"聊天邀请弹窗:{按钮名称}未赋值!"); return; } // 确保按钮所在对象激活 if (!按钮.gameObject.activeSelf) 按钮.gameObject.SetActive(true); // 确保按钮组件启用 按钮.enabled = true; 按钮.interactable = true; // 确保有图像组件(用于接收点击) if (按钮.GetComponent<Image>() == null) { Image img = 按钮.gameObject.AddComponent<Image>(); img.color = new Color(0, 0, 0, 0); // 透明背景 Debug.LogWarning($"聊天邀请弹窗:{按钮名称}缺少Image组件,已自动添加透明背景"); } // 确保有EventTrigger组件 if (按钮.GetComponent<EventTrigger>() == null) 按钮.gameObject.AddComponent<EventTrigger>(); } // 绑定按钮事件 private void 绑定按钮事件() { // 清除现有事件避免重复绑定 接受按钮?.onClick.RemoveAllListeners(); 拒绝按钮?.onClick.RemoveAllListeners(); // 绑定点击事件 if (接受按钮 != null) { 接受按钮.onClick.AddListener(On接受按钮点击); 初始化按钮交互(接受按钮); } if (拒绝按钮 != null) { 拒绝按钮.onClick.AddListener(On拒绝按钮点击); 初始化按钮交互(拒绝按钮); } } // 初始化按钮交互动画和事件 private void 初始化按钮交互(Button 按钮) { EventTrigger trigger = 按钮.GetComponent<EventTrigger>(); trigger.triggers.Clear(); // 鼠标进入事件 var enterEvent = new EventTrigger.Entry(); enterEvent.eventID = EventTriggerType.PointerEnter; enterEvent.callback.AddListener((data) => { Debug.Log($"{按钮.name}:鼠标进入"); 按钮.transform.DOScale(按钮缩放比例, 0.15f); }); trigger.triggers.Add(enterEvent); // 鼠标离开事件 var exitEvent = new EventTrigger.Entry(); exitEvent.eventID = EventTriggerType.PointerExit; exitEvent.callback.AddListener((data) => { Debug.Log($"{按钮.name}:鼠标离开"); 按钮.transform.DOScale(1f, 0.15f); }); trigger.triggers.Add(exitEvent); // 鼠标按下事件 var downEvent = new EventTrigger.Entry(); downEvent.eventID = EventTriggerType.PointerDown; downEvent.callback.AddListener((data) => { Debug.Log($"{按钮.name}:鼠标按下"); }); trigger.triggers.Add(downEvent); } // 显示弹窗(简化版) public void 显示弹窗(Action 接受回调函数, Action 拒绝回调函数) { 显示弹窗(默认标题, 默认内容, 接受回调函数, 拒绝回调函数); } // 显示弹窗(完整版) public void 显示弹窗(string 标题, string 内容, Action 接受回调函数, Action 拒绝回调函数) { // 如果当前有弹窗显示,加入队列等待 if (正在显示) { 弹窗队列.Enqueue(new 弹窗数据 { 标题 = 标题, 内容 = 内容, 接受回调 = 接受回调函数, 拒绝回调 = 拒绝回调函数 }); Debug.Log($"弹窗加入队列,当前队列长度:{弹窗队列.Count}"); return; } // 直接显示弹窗 内部显示弹窗(标题, 内容, 接受回调函数, 拒绝回调函数); } // 内部显示逻辑(核心修复:确保激活状态) private void 内部显示弹窗(string 标题, string 内容, Action 接受回调函数, Action 拒绝回调函数) { // 保存回调 接受回调 = 接受回调函数; 拒绝回调 = 拒绝回调函数; // 1. 确保整个弹窗层级处于激活状态 确保对象激活(); // 2. 设置文本内容 if (标题文本 != null) 标题文本.text = 标题; if (内容文本 != null) 内容文本.text = 内容; if (倒计时文本 != null) 倒计时文本.text = $"({超时时间}s)"; // 3. 重置画布组状态 弹窗画布组.alpha = 0; 弹窗画布组.interactable = true; 弹窗画布组.blocksRaycasts = true; // 4. 播放显示动画 弹窗画布组.DOFade(1, 动画时长).SetEase(Ease.OutQuad); 邀请窗口.transform.localScale = Vector3.zero; 邀请窗口.transform.DOScale(1, 动画时长).SetEase(Ease.OutBack); // 5. 安全启动协程(核心修复点) 启动倒计时协程(); 正在显示 = true; Debug.Log("弹窗显示成功"); } // 确保对象处于激活状态 private void 确保对象激活() { // 确保脚本所在对象激活 if (!gameObject.activeSelf) { gameObject.SetActive(true); Debug.Log("脚本所在对象已激活"); } // 确保弹窗根对象激活 if (!邀请窗口.activeSelf) { 邀请窗口.SetActive(true); Debug.Log("弹窗根对象已激活"); } // 确保整个层级处于激活状态 if (!gameObject.activeInHierarchy) { Debug.LogWarning("弹窗对象在非激活的父层级中,尝试修复..."); // 递归激活所有父对象 Transform current = transform; while (current != null && !current.gameObject.activeSelf) { current.gameObject.SetActive(true); current = current.parent; } } } // 安全启动倒计时协程 private void 启动倒计时协程() { // 先停止可能存在的旧协程 if (倒计时协程 != null) { StopCoroutine(倒计时协程); 倒计时协程 = null; } // 检查是否可以启动协程 if (isActiveAndEnabled && gameObject.activeInHierarchy) { 倒计时协程 = StartCoroutine(倒计时逻辑()); Debug.Log("倒计时协程已启动"); } else { Debug.LogError("无法启动协程:对象或脚本未激活!"); // 紧急处理:强制激活后重试 gameObject.SetActive(true); 邀请窗口.SetActive(true); 倒计时协程 = StartCoroutine(倒计时逻辑()); } } // 倒计时逻辑 private IEnumerator 倒计时逻辑() { float 剩余时间 = 超时时间; while (剩余时间 > 0 && 正在显示) { 剩余时间 -= Time.deltaTime; if (倒计时文本 != null) 倒计时文本.text = $"({Mathf.Ceil(剩余时间)}s)"; yield return null; } // 超时自动处理 if (正在显示) { Debug.Log("弹窗超时,自动关闭"); 隐藏弹窗(() => 拒绝回调?.Invoke()); } } // 隐藏弹窗 public void 隐藏弹窗(Action 完成回调 = null) { if (!正在显示) return; // 停止倒计时 if (倒计时协程 != null) { StopCoroutine(倒计时协程); 倒计时协程 = null; } // 播放淡出动画 弹窗画布组.DOFade(0, 动画时长).SetEase(Ease.InQuad) .OnComplete(() => { // 关键:只隐藏视觉效果,不禁用对象 弹窗画布组.interactable = false; 弹窗画布组.blocksRaycasts = false; 正在显示 = false; // 执行回调 完成回调?.Invoke(); // 显示下一个弹窗(如果有) if (弹窗队列.Count > 0) { 弹窗数据 下一个弹窗 = 弹窗队列.Dequeue(); 内部显示弹窗(下一个弹窗.标题, 下一个弹窗.内容, 下一个弹窗.接受回调, 下一个弹窗.拒绝回调); } Debug.Log("弹窗已隐藏"); }); } // 接受按钮点击 private void On接受按钮点击() { Debug.Log("接受按钮被点击"); 隐藏弹窗(() => { 接受回调?.Invoke(); if (聊天框 != null) { 聊天框.SetActive(true); Debug.Log("聊天框已显示"); } }); } // 拒绝按钮点击 private void On拒绝按钮点击() { Debug.Log("拒绝按钮被点击"); 隐藏弹窗(() => 拒绝回调?.Invoke()); } // 清理资源 private void OnDestroy() { DOTween.KillAll(); 弹窗队列.Clear(); } }
08-31
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三轮车上的礼物

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值