Files
5.24BuYu/Assets/MyGame/aa/UI/Game/ChineseChess/ChineseChessMainPanel.cs
T
2026-09-13 01:47:54 +08:00

739 lines
27 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.
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认输
}
/// <summary>
/// GoldConfigRequired Socket 推送数据
/// </summary>
[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<string,ChessGameRoom> dic_RoomData=new Dictionary<string, ChessGameRoom>();
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;
[Header("ChessGame 象棋对局")]
public UIChessBoard chessBoard; // 棋盘控件(Inspector 手动拖入;留空则运行时自动生成)
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 动画辅助
/// <summary>激活/禁用 Spine(不用时禁用节省性能,用时激活)</summary>
public void ActiveSpine(bool active)
{
if (skeletonGraphic == null) return;
if (skeletonGraphic.gameObject.activeSelf != active)
skeletonGraphic.gameObject.SetActive(active);
}
/// <summary>设置 Spine skin(切换皮肤并重置 slot)</summary>
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();
}
/// <summary>播放 Spine 动画</summary>
public void PlaySpineAnim(string animName, bool loop = true)
{
if (skeletonGraphic == null || string.IsNullOrEmpty(animName)) return;
ActiveSpine(true);
skeletonGraphic.AnimationState.SetAnimation(0, animName, loop);
}
/// <summary>切换到"正在匹配"状态</summary>
public void Spine_ZhengZaiPiPei()
{
SetSpineSkin(skineName_ZhengZaiPiPei);
PlaySpineAnim(animName_Loop, true);
}
/// <summary>切换到"匹配成功"状态:Open → 完成后播 Close → 禁用</summary>
public void Spine_PiPeiChengGong()
{
SetSpineSkin(skineName_PiPeiChengGong);
PlaySpineAnim(animName_Open, false);
// Open 播完后播 Close,然后禁用 Spine
StartCoroutine(DelayedSpineClose());
}
/// <summary>Open 动画播完后播放 Close 动画并禁用 Spine</summary>
private IEnumerator DelayedSpineClose()
{
// 等 Open 动画播完
yield return new WaitForSeconds(0.5f);
PlaySpineAnim(animName_Close, false);
// Close 播完后禁用 Spine
yield return new WaitForSeconds(0.5f);
ActiveSpine(false);
}
/// <summary>切换到"开始游戏"状态(短暂过渡)</summary>
public void Spine_KaiShi()
{
SetSpineSkin(skineName_KaiShi);
PlaySpineAnim(animName_Open, false);
}
/// <summary>切换到"进行中"状态</summary>
public void Spine_JinXingZhong()
{
SetSpineSkin(skineName_JinXingZhong);
PlaySpineAnim(animName_Loop, true);
}
/// <summary>延迟切换到"进行中"状态(等 KaiShi 过渡动画播完)</summary>
private IEnumerator DelayedSpine_JinXingZhong()
{
// 等待开始过渡动画播放完(默认 0.5s)
yield return new WaitForSeconds(0.5f);
Spine_JinXingZhong();
}
/// <summary>KaiShi 动画流程:Open 播完后切 Loop 播一小会,再播 Close 关闭并禁用</summary>
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
/// <summary>
/// 加载头像精灵(优先使用缓存,否则异步下载)
/// </summary>
public static void LoadAvatar(Image target, string avatarUrl, System.Action<Sprite> 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<Sprite> 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<WebSocketResponseBase<ChessGameRoom>>(msg.ToString());
ChessGameRoom chessGameRoom = va.arguments[0];
roomData = chessGameRoom; // 记录房间数据(开象棋对局时要取阵营)
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;
}
}
/// <summary>
/// 服务端推送 GoldConfigRequired → 显示金币设置面板(红方配置)
/// data: { targetUserId, room }
/// </summary>
public void OnGoldConfigRequired(string msg)
{
StopWaitCountdown();
var result = JsonConvert.DeserializeObject<WebSocketResponseBase<GoldConfigRequiredData>>(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);
}
/// <summary>
/// 显示/隐藏等待中(连带控制父对象链)
/// </summary>
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)
{
// 悔棋回执:直接处理,不弹窗
if (type == 4) // 对方同意悔棋 → 本地悔一步
{
OnUndoAgreed();
return;
}
if (type == 5) // 对方拒绝悔棋
{
if (chessBoard != null) chessBoard.ShowToast("对方拒绝悔棋");
return;
}
// 1求和 2认输 3悔棋请求 → 走之前的确认弹窗
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());
// 初始化象棋对局(普通管理类统一在此控制)
StartChessGame();
btn_QiuHe.onClick.RemoveAllListeners();
btn_RenShu.onClick.RemoveAllListeners();
btn_HuiQi.onClick.RemoveAllListeners();
btn_HuiQi.onClick.AddListener(RequestUndoChess);
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
});
});
}
#region 象棋对局(普通管理类统一在面板控制)
/// <summary>象棋对局总管理器(普通类)</summary>
private ChessGameManager chessGameManager;
/// <summary>运行时自动生成的棋盘(用于退出时销毁)</summary>
private RectTransform autoChessBoardRect;
/// <summary>
/// 开始一局象棋(双方准备完毕,InitRoomData 里调用)
/// 所有规则/走法本地运算(帧同步),后端只透传数据与结算胜负
/// </summary>
private void StartChessGame()
{
if (roomData == null || roomData.users == null) return;
// 我的阵营:RedisGameUser.type 1 黑方 2 红方
var me = roomData.users.Find(u => u.userId == GameManager.Instance.user.BaseInfo.number);
ChessCamp myCamp = me != null ? (ChessCamp)me.type : ChessCamp.Red;
chessGameManager = new ChessGameManager();
chessGameManager.OnMoveApplied += OnChessMoveApplied;
chessGameManager.OnGameOver += OnChessGameOver;
chessGameManager.OnTurnChanged += OnChessTurnChanged; // 要在 StartGame 前订阅(开局红先会触发一次)
chessGameManager.StartGame(myCamp);
if (chessBoard == null) CreateDefaultChessBoard();
chessBoard.Init(chessGameManager, myCamp);
}
/// <summary>面板上没拖棋盘控件时,自动生成一个(不依赖任何预制体/资源,定位点也自动建好)</summary>
private void CreateDefaultChessBoard()
{
var go = new GameObject("ChessBoard_Auto", typeof(RectTransform));
var rt = go.GetComponent<RectTransform>();
rt.SetParent(transform, false);
var prt = (RectTransform)transform;
float pw = prt.rect.width > 10f ? prt.rect.width : 1080f;
float ph = prt.rect.height > 10f ? prt.rect.height : 1920f;
float step = Mathf.Min(pw * 0.96f / 9f, ph * 0.88f / 10.1f);
rt.anchorMin = rt.anchorMax = new Vector2(0.5f, 0.5f);
rt.anchoredPosition = new Vector2(0f, -step * 0.4f); // 稍微下移,避开上方对手信息
rt.sizeDelta = new Vector2(step * 9f, step * 10.1f);
chessBoard = go.AddComponent<UIChessBoard>();
// 自动生成时:代码自建两个定位点(逻辑 (0,4) 与 (0,5),网格铺满棋盘区域)
// 逻辑 (0,4) = (-4*step, -0.5*step),逻辑 (0,5) = (-4*step, +0.5*step)(棋盘中心为原点)
var ps = new GameObject("Point_Start", typeof(RectTransform)).GetComponent<RectTransform>();
ps.SetParent(rt, false);
ps.anchoredPosition = new Vector2(-4f * step, -0.5f * step);
var pe = new GameObject("Point_End", typeof(RectTransform)).GetComponent<RectTransform>();
pe.SetParent(rt, false);
pe.anchoredPosition = new Vector2(-4f * step, 0.5f * step);
chessBoard.point_Start = ps;
chessBoard.point_End = pe;
autoChessBoardRect = rt;
}
/// <summary>本地走子成功 → 帧同步给对方(走 SyncGameData 通道,后端只透传)</summary>
private void OnChessMoveApplied(ChessMoveEventArgs e)
{
if (!e.isLocal) return; // 对方同步过来的不回发
SendChessNetData(new ChessNetData { msgType = 1, move = e.move });
}
/// <summary>对局结束(本地规则判定)→ 上报后端结算 + 弹结果面板</summary>
private void OnChessGameOver(ChessCamp winner)
{
StopWaitCountdown(); // 对局结束,停走棋倒计时
bool iWin = winner == chessGameManager.myCamp;
if (iWin)
{
// 只有赢家上报(避免双端重复),EndGame 第二个参数为胜者 userId
WebSocketSendList.EndGameChineseChess(roomData.roomId, GameManager.Instance.user.BaseInfo.number);
subUIManager.ShowAsync(UIPanel.ZGXQWin);
}
else
{
subUIManager.ShowAsync(UIPanel.ZGXQDefeated);
}
}
/// <summary>悔棋按钮 → 走之前写好的 GameOperation 通道(1求和 2认输 3悔棋),对方确认后双方各悔一步</summary>
private void RequestUndoChess()
{
if (chessGameManager == null || chessGameManager.isGameOver) return;
if (chessGameManager.recorder.Count == 0)
{
if (chessBoard != null) chessBoard.ShowToast("暂无可悔的棋步");
return;
}
WebSocketSendList.GameOperationChineseChess(roomData.roomId, 3, GameManager.Instance.user.BaseInfo.number);
if (chessBoard != null) chessBoard.ShowToast("已发送悔棋请求");
}
/// <summary>同意对方的悔棋请求(UIChineseChessHint 的同意按钮调用):回执已由弹窗发送,这里本地悔一步</summary>
public void AgreeUndoChess()
{
if (chessGameManager == null) return;
chessGameManager.UndoOneStep();
}
/// <summary>收到对方同意悔棋的回执(IsShowHint type=4):本地悔一步</summary>
private void OnUndoAgreed()
{
if (chessGameManager == null) return;
chessGameManager.UndoOneStep();
if (chessBoard != null) chessBoard.ShowToast("对方同意悔棋");
}
#region 对局走棋倒计时(复用原有倒计时字段:waitCountdown / StopWaitCountdown / tmp_WaitTime_Bottom、Top)
/// <summary>每回合倒计时秒数(用服务端房间配置 timeoutSeconds,没配默认 60)</summary>
private int ChessTurnSeconds => roomData != null && roomData.timeoutSeconds > 0 ? roomData.timeoutSeconds : 60;
/// <summary>回合切换 → 重新开始走棋倒计时(当前回合方的信息栏显示)</summary>
private void OnChessTurnChanged(ChessCamp camp)
{
if (chessGameManager == null || chessGameManager.isGameOver) return;
bool myTurn = camp == chessGameManager.myCamp;
if (waitCountdown != null) StopCoroutine(waitCountdown);
waitCountdown = StartCoroutine(TurnCountdownRoutine(ChessTurnSeconds, myTurn));
}
/// <summary>
/// 走棋倒计时:轮到我 → 显示在下方(超时 AI 自动走一步,不判负不结算);
/// 轮到对方 → 显示在上方(对方客户端超时同样由它的 AI 自动走)
/// </summary>
private IEnumerator TurnCountdownRoutine(int totalSeconds, bool myTurn)
{
int remaining = totalSeconds;
while (remaining >= 0)
{
string timeStr = $"{remaining / 60:D2}:{remaining % 60:D2}";
if (myTurn)
{
if (tmp_WaitTime_Bottom != null) tmp_WaitTime_Bottom.text = $"请走棋 {timeStr}";
if (tmp_WaitTime_Top != null) tmp_WaitTime_Top.text = "";
}
else
{
if (tmp_WaitTime_Top != null) tmp_WaitTime_Top.text = $"对方走棋 {timeStr}";
if (tmp_WaitTime_Bottom != null) tmp_WaitTime_Bottom.text = "";
}
yield return new WaitForSeconds(1f);
remaining--;
}
if (myTurn)
{
// 我方超时 → AI 自动走一步(走完会触发回合切换,倒计时自动重开)
if (chessGameManager != null && !chessGameManager.isGameOver)
{
bool moved = chessGameManager.AutoMove();
if (moved && chessBoard != null) chessBoard.ShowToast("超时,已自动走子");
}
}
// 对方回合超时:对方客户端同样 AI 自动走一步,我方等它的走子帧
}
#endregion
/// <summary>发送象棋帧同步数据(SyncGameData 通道)</summary>
private void SendChessNetData(ChessNetData data)
{
if (roomData == null || chessGameManager == null || data == null) return;
data.userId = GameManager.Instance.user.BaseInfo.number;
WebSocketSendList.SyncGameDataChineseChess(roomData.roomId, JsonConvert.SerializeObject(data));
}
/// <summary>
/// 收到 SyncGameData 推送(由 WebSocketManager_Message 的 SyncGameData 分支调用)
/// 兼容 arguments[0] = {"data":"..."} 与 arguments = [gameId, data] 两种回包格式
/// </summary>
public void OnChessNetData(string rawMsg)
{
if (chessGameManager == null) return;
try
{
var resp = JsonConvert.DeserializeObject<WebSocketResponseBase<Newtonsoft.Json.Linq.JToken>>(rawMsg);
if (resp == null || resp.arguments == null) return;
foreach (var arg in resp.arguments)
{
string dataStr = null;
if (arg.Type == Newtonsoft.Json.Linq.JTokenType.String
&& arg.ToString().TrimStart().StartsWith("{"))
{
dataStr = arg.ToString();
}
else if (arg.Type == Newtonsoft.Json.Linq.JTokenType.Object && arg["data"] != null)
{
dataStr = arg["data"].ToString();
}
if (!string.IsNullOrEmpty(dataStr)) HandleChessNetData(dataStr);
}
}
catch (Exception ex)
{
Debug.LogWarning("[ChineseChess] SyncGameData 解析失败: " + ex.Message);
}
}
/// <summary>处理对方发来的走棋帧(悔棋/认输/求和走 GameOperation 通道,不经过这里)</summary>
private void HandleChessNetData(string dataStr)
{
ChessNetData net;
try { net = JsonConvert.DeserializeObject<ChessNetData>(dataStr); }
catch { return; }
if (net == null || string.IsNullOrEmpty(net.userId)) return;
// 服务器回声/自己发的帧直接忽略
if (net.userId == GameManager.Instance.user.BaseInfo.number) return;
if (net.msgType == 1) // 对方走棋
{
chessGameManager.ApplyRemoteMove(net.move);
}
}
/// <summary>清理对局(面板隐藏时调用)</summary>
private void ClearChessGame()
{
if (chessGameManager != null)
{
chessGameManager.OnMoveApplied -= OnChessMoveApplied;
chessGameManager.OnGameOver -= OnChessGameOver;
chessGameManager.OnTurnChanged -= OnChessTurnChanged;
chessGameManager = null;
}
StopWaitCountdown(); // 停走棋倒计时
if (chessBoard != null) chessBoard.Clear();
if (autoChessBoardRect != null)
{
Destroy(autoChessBoardRect.gameObject);
autoChessBoardRect = null;
chessBoard = null;
}
}
#endregion
public void Start()
{
}
/// <summary>
/// 开始等待倒计时
/// </summary>
/// <param name="seconds">总秒数</param>
/// <param name="type">倒计时类型</param>
/// <param name="waitMsg">等待时显示的文字,如"等待玩家进入"</param>
public void StartWaitCountdown(int seconds, CountdownType type = CountdownType.WaitPlayer, string waitMsg = null)
{
if (waitCountdown != null) StopCoroutine(waitCountdown);
waitCountdown = StartCoroutine(WaitCountdownRoutine(seconds, type, waitMsg));
}
/// <summary>
/// 停止等待倒计时
/// </summary>
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();
// 清理象棋对局
ClearChessGame();
// 退出:播放 Close 动画后禁用 Spine
PlaySpineAnim(animName_Close, false);
ActiveSpine(false);
WebSocketManager.Instance.Close(SocketType.chess);
Screen.orientation = ScreenOrientation.LandscapeLeft;
}
}