From 5fc782e43beaaf7117f57fb8679000653a1b20ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A3=AE2003?= <2384017988@qq.com> Date: Mon, 5 Oct 2026 02:54:15 +0800 Subject: [PATCH] 1 --- .../aa/UI/Game/XJMH/GameMainPanel_XJMH.cs | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/Assets/MyGame/aa/UI/Game/XJMH/GameMainPanel_XJMH.cs b/Assets/MyGame/aa/UI/Game/XJMH/GameMainPanel_XJMH.cs index b12f64939..e265a44e0 100644 --- a/Assets/MyGame/aa/UI/Game/XJMH/GameMainPanel_XJMH.cs +++ b/Assets/MyGame/aa/UI/Game/XJMH/GameMainPanel_XJMH.cs @@ -132,6 +132,19 @@ public class GameMainPanel_XJMH : GameMainPanel_FishBase [Tooltip("提示文案(预制体默认「正在连接服务器...」)")] public string waitTipMessage = "正在连接服务器..."; + // ==================== 免费模式框(原版 PW_Battery_FreeFrame_L/R) ==================== + [Header("免费模式框(原版 PW_Battery_FreeFrame_L/R)")] + [Tooltip("左侧免费模式框:拖 Assets/Art/XJMH/pw/pw_prefab/game/battery/PW_Battery_FreeFrame_L.prefab 的实例(建议摆在左侧座位炮台下方,初始自动隐藏)")] + public GameObject freeFrameL; + [Tooltip("右侧免费模式框:拖 PW_Battery_FreeFrame_R.prefab 实例(建议摆在右侧座位炮台下方)")] + public GameObject freeFrameR; + [Tooltip("自己进入免费模式时的滑入距离(像素,原版 200)")] + public float freeFrameSlideDistance = 200f; + [Tooltip("滑入时长(秒,原版 0.4)")] + public float freeFrameSlideInTime = 0.4f; + [Tooltip("滑出时长(秒,原版 0.3)")] + public float freeFrameSlideOutTime = 0.3f; + [Header("核弹列表动画(照原版 Rocket 逐项弹出)")] [Tooltip("相邻条目的弹出/收缩间隔(秒),原版 0.1")] public float nukeItemStagger = 0.1f; @@ -155,6 +168,7 @@ public class GameMainPanel_XJMH : GameMainPanel_FishBase InitSetPanel(); InitExitView(); InitWaitTip(); + InitFreeFrame(); } public override void Start() @@ -297,6 +311,11 @@ public class GameMainPanel_XJMH : GameMainPanel_FishBase // 重连等待提示:离场立即收起 if (waitTipPanel != null) waitTipPanel.SetActive(false); + + // 免费模式框:离场立即收起并清动画 + _freeFrameActive = null; + ResetFreeFrameView(_freeFrameL); + ResetFreeFrameView(_freeFrameR); } /// @@ -1665,6 +1684,163 @@ public class GameMainPanel_XJMH : GameMainPanel_FishBase }, }; + // ==================== 免费模式框(原版 PW_Battery_FreeFrame_L/R) ==================== + // 移植自原版 PW_Battery.txt(SetFreeMode / ShowFreeFrame / HideFreeFrame / FreeModeUpdate): + // - 免费模式开启 → 显示对应侧的框:FreeImage(免费图标)+ FreeTime(倒计时 Time,一位小数) + // - 自己(isSelf):先收起 FreeImage/FreeTime,框从屏外侧滑入(原版 0.4s),落位后才显示; + // 同时显示 Frame(buff 图标列表 + Num 数量);结束时滑出(原版 0.3s)后才隐藏 + // - 其它玩家:立即显示 FreeImage/FreeTime、不显示 Frame;结束直接隐藏 + // - 原版按座位侧加载 L/R(IsLeft = chairId==1),这里由调用方传 isLeft 选择;一次只显示一侧 + // - 原版其它玩家的 FreeImage/FreeTime 会吸附到该炮台 bottom/FreeImagePos、FreeTimePos 锚点; + // 新炮台没有这两个锚点,这里直接用预制体摆放位置(拖框时摆到对应座位炮台下方即可) + // - ⚠️ 免费 buff 数据链(SetFreeMode/UseNextBuff/BuffFinish 的服务器同步)本项目还没接; + // 数据接上后调用以下公开 API 即可:ShowFreeFrame / UpdateFreeFrameTime / SetFreeFrameBuffCount / HideFreeFrame + + /// 一侧免费模式框的节点与初始位置(左右各一份) + private sealed class XjmhFreeFrameView + { + public GameObject root; // PW_Battery_FreeFrame_L / R + public RectTransform rootRt; + public Vector2 home; // 预制体摆放位置(滑入落点 / 滑出起点) + public GameObject freeImage; // FreeImage + public GameObject freeTime; // FreeTime + public Transform timeText; // FreeTime/Time(倒计时文本) + public GameObject frame; // Frame(自己才有:buff 图标列表 + Num) + public bool selfShown; // 本次显示是否走的"自己"(决定收起时是否滑出) + } + + private XjmhFreeFrameView _freeFrameL; + private XjmhFreeFrameView _freeFrameR; + private XjmhFreeFrameView _freeFrameActive; // 当前在显示的框(一次只会有一侧) + + /// 免费模式框初始化:抓节点、记录原位、初始隐藏 + private void InitFreeFrame() + { + _freeFrameL = BuildFreeFrameView(freeFrameL); + _freeFrameR = BuildFreeFrameView(freeFrameR); + } + + private XjmhFreeFrameView BuildFreeFrameView(GameObject root) + { + if (root == null) return null; + + var v = new XjmhFreeFrameView + { + root = root, + rootRt = root.transform as RectTransform, + freeImage = FindChildByName(root.transform, "FreeImage")?.gameObject, + freeTime = FindChildByName(root.transform, "FreeTime")?.gameObject, + timeText = FindChildByName(root.transform, "Time"), + frame = FindChildByName(root.transform, "Frame")?.gameObject, + }; + if (v.rootRt != null) v.home = v.rootRt.anchoredPosition; + + root.SetActive(false); // 初始隐藏(原版 freeFrame:SetActive(false)) + return v; + } + + /// + /// 显示免费模式框(原版 Battery:ShowFreeFrame): + /// 自己 → Frame 显示 + 从屏外滑入、落位后才显示 FreeImage/FreeTime;其它玩家 → 立即显示、不显示 Frame。 + /// + public void ShowFreeFrame(bool isLeft, bool isSelf) + { + var v = isLeft ? _freeFrameL : _freeFrameR; + var other = isLeft ? _freeFrameR : _freeFrameL; + if (v == null || v.root == null) return; + + // 另一侧若在显示:立即收起(原版每台炮台各自一份,这里面板级一次只显示一侧) + if (other != null && other.root != null) + { + if (other.rootRt != null) other.rootRt.DOKill(); + other.root.SetActive(false); + } + + _freeFrameActive = v; + v.selfShown = isSelf; + v.root.SetActive(true); + if (v.frame != null) v.frame.SetActive(isSelf); // 原版:只有自己显示 Frame + + if (isSelf && v.rootRt != null) + { + // 原版:先收起 FreeImage/FreeTime,从屏外滑入,onEnd 才 ActiveFreeTimeAndImagePos + SetFreeFrameInfoActive(v, false); + var rt = v.rootRt; + rt.DOKill(); + rt.anchoredPosition = new Vector2(v.home.x + (isLeft ? -freeFrameSlideDistance : freeFrameSlideDistance), v.home.y); + rt.DOAnchorPos(v.home, freeFrameSlideInTime) + .OnComplete(() => SetFreeFrameInfoActive(v, true)); + } + else + { + SetFreeFrameInfoActive(v, true); + } + } + + /// 隐藏免费模式框(原版 Battery:HideFreeFrame):自己先滑出再隐藏,其它玩家直接隐藏 + public void HideFreeFrame() + { + var v = _freeFrameActive; + _freeFrameActive = null; + if (v == null || v.root == null) return; + + SetFreeFrameInfoActive(v, false); + if (v.frame != null) v.frame.SetActive(false); + + if (v.selfShown && v.rootRt != null) + { + var rt = v.rootRt; + rt.DOKill(); + float outX = v.home.x + ((v == _freeFrameL) ? -freeFrameSlideDistance : freeFrameSlideDistance); + rt.DOAnchorPos(new Vector2(outX, v.home.y), freeFrameSlideOutTime) + .OnComplete(() => { if (v.root != null) v.root.SetActive(false); }); + } + else + { + if (v.rootRt != null) v.rootRt.DOKill(); + v.root.SetActive(false); + } + v.selfShown = false; + } + + /// 免费倒计时(原版 FreeModeUpdate:freeTimeText = string.format("%.1f", remain)) + public void UpdateFreeFrameTime(float remainSeconds) + { + var v = _freeFrameActive; + if (v == null || v.timeText == null) return; + SetTextContent(v.timeText, remainSeconds.ToString("F1")); + } + + /// buff 图标数量(原版 Frame/Num = #freeBuffList) + public void SetFreeFrameBuffCount(int count) + { + var v = _freeFrameActive; + if (v == null || v.frame == null) return; + SetTextContent(FindChildByName(v.frame.transform, "Num"), count.ToString()); + } + + /// FreeImage/FreeTime 显隐(原版 ActiveFreeTimeAndImagePos / Deactive) + private static void SetFreeFrameInfoActive(XjmhFreeFrameView v, bool active) + { + if (v.freeImage != null) v.freeImage.SetActive(active); + if (v.freeTime != null) v.freeTime.SetActive(active); + } + + /// 立即复位(离场清理:停动画、回原位、全部隐藏) + private static void ResetFreeFrameView(XjmhFreeFrameView v) + { + if (v == null || v.root == null) return; + if (v.rootRt != null) + { + v.rootRt.DOKill(); + v.rootRt.anchoredPosition = v.home; + } + SetFreeFrameInfoActive(v, false); + if (v.frame != null) v.frame.SetActive(false); + v.selfShown = false; + v.root.SetActive(false); + } + // ==================== 断线重连等待提示(Hl_WaitTip) ==================== // socket 断线自动重连期间显示"正在连接服务器..."全屏等待提示(原版重连等待的等价物): // - 重连状态来自 WebSocketManager.OnReconnectingChanged(事件在重连协程的开始/结束点统一广播,