This commit is contained in:
2026-10-05 02:54:15 +08:00
parent 06e1a12ae2
commit 5fc782e43b
@@ -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);
}
/// <summary>
@@ -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
/// <summary>一侧免费模式框的节点与初始位置(左右各一份)</summary>
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; // 当前在显示的框(一次只会有一侧)
/// <summary>免费模式框初始化:抓节点、记录原位、初始隐藏</summary>
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;
}
/// <summary>
/// 显示免费模式框(原版 Battery:ShowFreeFrame):
/// 自己 → Frame 显示 + 从屏外滑入、落位后才显示 FreeImage/FreeTime;其它玩家 → 立即显示、不显示 Frame。
/// </summary>
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);
}
}
/// <summary>隐藏免费模式框(原版 Battery:HideFreeFrame):自己先滑出再隐藏,其它玩家直接隐藏</summary>
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;
}
/// <summary>免费倒计时(原版 FreeModeUpdate:freeTimeText = string.format("%.1f", remain))</summary>
public void UpdateFreeFrameTime(float remainSeconds)
{
var v = _freeFrameActive;
if (v == null || v.timeText == null) return;
SetTextContent(v.timeText, remainSeconds.ToString("F1"));
}
/// <summary>buff 图标数量(原版 Frame/Num = #freeBuffList)</summary>
public void SetFreeFrameBuffCount(int count)
{
var v = _freeFrameActive;
if (v == null || v.frame == null) return;
SetTextContent(FindChildByName(v.frame.transform, "Num"), count.ToString());
}
/// <summary>FreeImage/FreeTime 显隐(原版 ActiveFreeTimeAndImagePos / Deactive)</summary>
private static void SetFreeFrameInfoActive(XjmhFreeFrameView v, bool active)
{
if (v.freeImage != null) v.freeImage.SetActive(active);
if (v.freeTime != null) v.freeTime.SetActive(active);
}
/// <summary>立即复位(离场清理:停动画、回原位、全部隐藏)</summary>
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(事件在重连协程的开始/结束点统一广播,