using Assets.MyGame.Scripts.Net; using Newtonsoft.Json; using Spine.Unity; using System; using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; using static Assets.MyGame.Scripts.Net.WebResponses.ChineseChess.ChineseChessGameClassList; public class HintData { public ChessGameRoom roomData; public int hintType; //1求和2认输 } /// /// GoldConfigRequired Socket 推送数据 /// [Serializable] public class GoldConfigRequiredData { public string targetUserId; public ChessGameRoom room; } public enum CountdownType { WaitPlayer, // 等待玩家进入,超时 → 退出到选房 WaitHostStart, // 等待房主开始游戏,超时 → 退出到选房 WaitSetCoin, // 等待设置金额,超时 → 退出到选房 WaitOpponent, // 等待对手操作,超时 → 自动处理 } public class ChineseChessMainPanel : GameMainPanel_Base { public Button btn_QiuHe; public Button btn_RenShu; public Button btn_HuiQi; public Button btn_SheZhi; public Button btn_GuiZe; public Button btn_StartGame; public Image img_DengDaiZhong; public ChessGameRoom roomData; public static Dictionary dic_RoomData=new Dictionary(); public Button btn_FanHuiDaTing; [Header("Bottom")] public TextMeshProUGUI tmp_Name_Bottom; public TextMeshProUGUI tmp_CoinCount_Bottom; public TextMeshProUGUI tmp_WaitTime_Bottom; public Image img_Title_Bottom; [Header("Top")] public TextMeshProUGUI tmp_Name_Top; public TextMeshProUGUI tmp_CoinCount_Top; public TextMeshProUGUI tmp_WaitTime_Top; public Image img_Title_Top; private Coroutine waitCountdown; public SkeletonGraphic skeletonGraphic; public string skineName_JinXingZhong; public string skineName_KaiShi; public string skineName_PiPeiChengGong; public string skineName_ZhengZaiPiPei; public string animName_Close; public string animName_Open; public string animName_Loop; #region Spine 动画辅助 /// 激活/禁用 Spine(不用时禁用节省性能,用时激活) public void ActiveSpine(bool active) { if (skeletonGraphic == null) return; if (skeletonGraphic.gameObject.activeSelf != active) skeletonGraphic.gameObject.SetActive(active); } /// 设置 Spine skin(切换皮肤并重置 slot) public void SetSpineSkin(string skinName) { if (skeletonGraphic == null || string.IsNullOrEmpty(skinName)) return; ActiveSpine(true); var skel = skeletonGraphic.Skeleton; if (skel == null) return; skel.SetSkin(skinName); skel.SetSlotsToSetupPose(); skeletonGraphic.LateUpdate(); } /// 播放 Spine 动画 public void PlaySpineAnim(string animName, bool loop = true) { if (skeletonGraphic == null || string.IsNullOrEmpty(animName)) return; ActiveSpine(true); skeletonGraphic.AnimationState.SetAnimation(0, animName, loop); } /// 切换到"正在匹配"状态 public void Spine_ZhengZaiPiPei() { SetSpineSkin(skineName_ZhengZaiPiPei); PlaySpineAnim(animName_Loop, true); } /// 切换到"匹配成功"状态:Open → 完成后播 Close → 禁用 public void Spine_PiPeiChengGong() { SetSpineSkin(skineName_PiPeiChengGong); PlaySpineAnim(animName_Open, false); // Open 播完后播 Close,然后禁用 Spine StartCoroutine(DelayedSpineClose()); } /// Open 动画播完后播放 Close 动画并禁用 Spine private IEnumerator DelayedSpineClose() { // 等 Open 动画播完 yield return new WaitForSeconds(0.5f); PlaySpineAnim(animName_Close, false); // Close 播完后禁用 Spine yield return new WaitForSeconds(0.5f); ActiveSpine(false); } /// 切换到"开始游戏"状态(短暂过渡) public void Spine_KaiShi() { SetSpineSkin(skineName_KaiShi); PlaySpineAnim(animName_Open, false); } /// 切换到"进行中"状态 public void Spine_JinXingZhong() { SetSpineSkin(skineName_JinXingZhong); PlaySpineAnim(animName_Loop, true); } /// 延迟切换到"进行中"状态(等 KaiShi 过渡动画播完) private IEnumerator DelayedSpine_JinXingZhong() { // 等待开始过渡动画播放完(默认 0.5s) yield return new WaitForSeconds(0.5f); Spine_JinXingZhong(); } /// KaiShi 动画流程:Open 播完后切 Loop 播一小会,再播 Close 关闭并禁用 private IEnumerator DelayedKaiShiLoopToClose() { // 等 Open 动画播完 yield return new WaitForSeconds(0.5f); // 切 Loop 动画播一小会 PlaySpineAnim(animName_Loop, true); yield return new WaitForSeconds(1f); // 播 Close 动画并禁用 Spine PlaySpineAnim(animName_Close, false); yield return new WaitForSeconds(0.5f); ActiveSpine(false); } #endregion /// /// 加载头像精灵(优先使用缓存,否则异步下载) /// public static void LoadAvatar(Image target, string avatarUrl, System.Action onLoaded = null) { if (target == null) return; var sprite = GameManager.Instance.GetAvatarSprite(avatarUrl); if (sprite != null) { target.sprite = sprite; onLoaded?.Invoke(sprite); return; } // 缓存未命中,通过 DownSprite 协程异步加载 GameManager.Instance.StartCoroutine(LoadAvatarCoroutine(target, avatarUrl, onLoaded)); } private static IEnumerator LoadAvatarCoroutine(Image target, string avatarUrl, System.Action onLoaded) { // 构造一个临时的 UserBaseInfo 对象来复用 DownSprite 逻辑 var tempInfo = new UserBaseInfo { avatarUrl = avatarUrl }; yield return tempInfo.DownSprite(sprite => { if (sprite != null && target != null) target.sprite = sprite; onLoaded?.Invoke(sprite); }); } public static string FormatGold(long gold) { if (gold >= 100000000) { // 截取两位小数,不四舍五入 long yi = gold / 100000000; long remainder = gold % 100000000; long decimals = remainder * 100 / 100000000; if (decimals > 0) return $"{yi}.{decimals:D2}亿"; return $"{yi}亿"; } if (gold >= 10000) { // 截取两位小数,不四舍五入 long wan = gold / 10000; long remainder = gold % 10000; long decimals = remainder * 100 / 10000; // 两位小数 if (decimals > 0) return $"{wan}.{decimals:D2}万"; return $"{wan}万"; } return gold.ToString(); } public void StartGame(string msg) { var va = JsonConvert.DeserializeObject>(msg.ToString()); ChessGameRoom chessGameRoom = va.arguments[0]; UpdateUserData(chessGameRoom); switch (chessGameRoom.users.Count) { case 1: { tmp_Name_Top.text = "等待玩家进入"; tmp_CoinCount_Top.text = ""; img_Title_Top.gameObject.SetActive(false); if (tmp_WaitTime_Bottom != null) tmp_WaitTime_Bottom.text = "等待玩家进入02:00"; if (tmp_WaitTime_Top != null) tmp_WaitTime_Top.text = "等待玩家进入02:00"; StartWaitCountdown(120, CountdownType.WaitPlayer, "等待玩家进入"); // 正在匹配 Spine_ZhengZaiPiPei(); } break; case 2: { StopWaitCountdown(); img_Title_Top.gameObject.SetActive(true); // 判断是否为房主 bool isRoomOwner = chessGameRoom.users.Count > 0 && chessGameRoom.users[0].userId == GameManager.Instance.user.BaseInfo.number; if (isRoomOwner) { btn_StartGame.gameObject.SetActive(true); btn_StartGame.onClick.RemoveAllListeners(); btn_StartGame.onClick.AddListener(() => { // 房主点击开始 → 发送 StartGame Socket 请求 btn_StartGame.gameObject.SetActive(false); StopWaitCountdown(); WebSocketSendList.StartGameChineseChess(chessGameRoom.roomId, GameManager.Instance.user.BaseInfo.number); }); } else { btn_StartGame.gameObject.SetActive(false); } StartWaitCountdown(60, CountdownType.WaitHostStart, "等待房主开始游戏"); // 匹配成功 Spine_PiPeiChengGong(); } break; default: break; } } /// /// 服务端推送 GoldConfigRequired → 显示金币设置面板(红方配置) /// data: { targetUserId, room } /// public void OnGoldConfigRequired(string msg) { StopWaitCountdown(); var result = JsonConvert.DeserializeObject>(msg); var data = result.arguments[0]; // 更新房间数据 if (data.room != null) { roomData = data.room; UpdateUserData(data.room); } // 判断当前用户是否为红方(targetUserId) bool isRedSide = data.targetUserId == GameManager.Instance.user.BaseInfo.number; if (isRedSide) { // 红方显示金币设置面板 subUIManager.ShowAsync(UIPanel.ZGXQSelectCoin, roomData); StartWaitCountdown(60, CountdownType.WaitSetCoin, "等待设置金额"); } else { // 黑方等待红方设置金币 StartWaitCountdown(60, CountdownType.WaitSetCoin, "等待对方设置金额"); } } public void UpdateUserData(ChessGameRoom chessGameRoom) { foreach (var item in chessGameRoom.users) { if (item.userId == GameManager.Instance.user.BaseInfo.number) { tmp_Name_Bottom.text ="ID:" + item.userId; tmp_CoinCount_Bottom.text = FormatGold(item.gold); LoadAvatar(img_Title_Bottom, item.userAvatar); } else { tmp_Name_Top.text ="ID:" + item.userId; tmp_CoinCount_Top.text = FormatGold(item.gold); LoadAvatar(img_Title_Top, item.userAvatar); } } } public override void Awake() { base.Awake(); btn_FanHuiDaTing.onClick.AddListener(() => { UIManager.Instance.Close(UIPanel.MainGamePanelZGXQ); }); btn_GuiZe.onClick.AddListener(() => { subUIManager.ShowAsync(UIPanel.ZGXQIntroduce); }); } protected override void OnShow(object args = null) { base.OnShow(args); // 回到选房间界面时显示等待中(连带父对象) SetDengDaiZhongActive(true); subUIManager.ShowAsync(UIPanel.ZGXQDistrict, args); // 选房阶段不使用 Spine,禁用 ActiveSpine(false); } /// /// 显示/隐藏等待中(连带控制父对象链) /// public void SetDengDaiZhongActive(bool active) { if (img_DengDaiZhong != null) { img_DengDaiZhong.gameObject.SetActive(active); } } public void IsShowHint(string id,int type) { if (GameManager.Instance.user.BaseInfo.number!=id) { subUIManager.ShowAsync(UIPanel.ZGXQHint, new HintData { roomData = roomData, hintType = type }); } } public void InitRoomData() { // 游戏已开始,停止所有倒计时 StopWaitCountdown(); // 关闭游戏说明面板(双方都准备完毕,进入进行中) subUIManager.Close(UIPanel.ZGXQGameExplain); // 双方都准备完毕:播放 KaiShi Spine 动画 Open → Loop 一小会 → Close Spine_KaiShi(); StartCoroutine(DelayedKaiShiLoopToClose()); btn_QiuHe.onClick.RemoveAllListeners(); btn_RenShu.onClick.RemoveAllListeners(); btn_QiuHe.onClick.AddListener(() => { WebSocketSendList.GameOperationChineseChess(roomData.roomId,1,GameManager.Instance.user.BaseInfo.number); }); btn_RenShu.onClick.AddListener(() => { //WebSocketSendList.GameOperationChineseChess(roomData.roomId, 2, GameManager.Instance.user.BaseInfo.number); subUIManager.ShowAsync(UIPanel.ZGXQHint, new HintData { roomData = roomData, hintType = 2 }); }); } public void Start() { } /// /// 开始等待倒计时 /// /// 总秒数 /// 倒计时类型 /// 等待时显示的文字,如"等待玩家进入" public void StartWaitCountdown(int seconds, CountdownType type = CountdownType.WaitPlayer, string waitMsg = null) { if (waitCountdown != null) StopCoroutine(waitCountdown); waitCountdown = StartCoroutine(WaitCountdownRoutine(seconds, type, waitMsg)); } /// /// 停止等待倒计时 /// public void StopWaitCountdown() { if (waitCountdown != null) { StopCoroutine(waitCountdown); waitCountdown = null; } if (tmp_WaitTime_Bottom != null) tmp_WaitTime_Bottom.text = ""; if (tmp_WaitTime_Top != null) tmp_WaitTime_Top.text = ""; } private IEnumerator WaitCountdownRoutine(int totalSeconds, CountdownType type, string waitMsg) { int remaining = totalSeconds; while (remaining >= 0) { string timeStr = $"{remaining / 60:D2}:{remaining % 60:D2}"; switch (type) { default: string displayText = string.IsNullOrEmpty(waitMsg) ? timeStr : $"{waitMsg}{timeStr}"; if (tmp_WaitTime_Bottom != null) tmp_WaitTime_Bottom.text = displayText; if (tmp_WaitTime_Top != null) tmp_WaitTime_Top.text = displayText; break; } yield return new WaitForSeconds(1f); remaining--; } switch (type) { default: // 超时:返回选房间界面 subUIManager.CloseAll(); WebSocketSendList.GetRoomListChineseChess(1); break; } } protected override void OnHide() { base.OnHide(); // 退出:播放 Close 动画后禁用 Spine PlaySpineAnim(animName_Close, false); ActiveSpine(false); WebSocketManager.Instance.Close(SocketType.chess); Screen.orientation = ScreenOrientation.LandscapeLeft; } }