This commit is contained in:
2026-10-11 22:29:54 +08:00
parent 0d53dc073d
commit 20cdf28cfa
3 changed files with 2311 additions and 2179 deletions
+21 -76
View File
@@ -878,6 +878,7 @@ MonoBehaviour:
m_Markers: m_Markers:
m_Objects: m_Objects:
- {fileID: 6527845954037689115} - {fileID: 6527845954037689115}
- {fileID: 7090975705886422730}
--- !u!114 &-4838957258320222283 --- !u!114 &-4838957258320222283
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 1 m_ObjectHideFlags: 1
@@ -2335,25 +2336,7 @@ MonoBehaviour:
m_RotationOrder: 4 m_RotationOrder: 4
m_MixOutCurve: m_MixOutCurve:
serializedVersion: 2 serializedVersion: 2
m_Curve: m_Curve: []
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
@@ -2545,25 +2528,7 @@ MonoBehaviour:
m_BlendOutDuration: 0 m_BlendOutDuration: 0
m_MixInCurve: m_MixInCurve:
serializedVersion: 2 serializedVersion: 2
m_Curve: m_Curve: []
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
@@ -2662,49 +2627,13 @@ MonoBehaviour:
m_BlendOutDuration: 1.3166666666666345 m_BlendOutDuration: 1.3166666666666345
m_MixInCurve: m_MixInCurve:
serializedVersion: 2 serializedVersion: 2
m_Curve: m_Curve: []
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
m_MixOutCurve: m_MixOutCurve:
serializedVersion: 2 serializedVersion: 2
m_Curve: m_Curve: []
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2 m_PreInfinity: 2
m_PostInfinity: 2 m_PostInfinity: 2
m_RotationOrder: 4 m_RotationOrder: 4
@@ -2845,6 +2774,22 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: fde0d25a170598d46a0b9dc16b4527a5, type: 3} m_Script: {fileID: 11500000, guid: fde0d25a170598d46a0b9dc16b4527a5, type: 3}
m_Name: ActivationPlayableAsset m_Name: ActivationPlayableAsset
m_EditorClassIdentifier: m_EditorClassIdentifier:
--- !u!114 &7090975705886422730
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3}
m_Name: Signal Emitter
m_EditorClassIdentifier:
m_Time: 10.466666666666667
m_Retroactive: 0
m_EmitOnce: 0
m_Asset: {fileID: 11400000, guid: 1508e534c5cd88d459d245dd3557a1c6, type: 2}
--- !u!114 &7132241618827546106 --- !u!114 &7132241618827546106
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 1 m_ObjectHideFlags: 1
+160 -30
View File
@@ -14,7 +14,8 @@ using UnityEngine;
/// 起飞入口:TakeoffToScreenPos(当前轻点路径,受 allowTapTakeoff 控制); /// 起飞入口:TakeoffToScreenPos(当前轻点路径,受 allowTapTakeoff 控制);
/// 将来"起飞按钮"接入后走同一入口即可(或在面板上打开 allowTapTakeoff 恢复轻点起飞)。 /// 将来"起飞按钮"接入后走同一入口即可(或在面板上打开 allowTapTakeoff 恢复轻点起飞)。
/// 交互判定在 GameMainPanel_FishBase.HandleInput(轻点=按下短+几乎没移动;按住扫射不触发起飞)。 /// 交互判定在 GameMainPanel_FishBase.HandleInput(轻点=按下短+几乎没移动;按住扫射不触发起飞)。
/// 挂载:XJMH 座位炮台(xjmhTurretList 中的子对象),飞机预制体挂在炮台节点下面(PW_Plane_x,默认隐藏)。 /// 挂载:XJMH 座位炮台(xjmhTurretList 中的子对象);飞机骨架挂在座位的变体容器节点里
/// (lvptfeiji/lanptfeiji/huangjinfeiji/vipfeiji01,与炮台平级,默认隐藏)——入场时临时挂到炮台下显示、结束还原。
/// 注意:不要在本类定义 Awake/OnEnable,会隐藏基类的同名私有初始化逻辑。 /// 注意:不要在本类定义 Awake/OnEnable,会隐藏基类的同名私有初始化逻辑。
/// </summary> /// </summary>
public class FlyTurretData : TurretData public class FlyTurretData : TurretData
@@ -305,7 +306,16 @@ public class FlyTurretData : TurretData
private Coroutine _enterRoutine; private Coroutine _enterRoutine;
private RectTransform _enterPlane; // 入场中的飞机节点(离场清理复位用) private RectTransform _enterPlane; // 入场中的飞机节点(离场清理复位用)
private Vector2 _enterPlaneHome; // 飞机停靠位(预制体配好的 anchoredPosition) private SkeletonGraphic _enterPlaneSg; // 飞机骨架(临时挂载后播 "stand01"/"back")
private bool _enterBoardHidden; // 入场期间 Board 被暂时隐藏(清理时只恢复自己隐藏的)
// ⭐ 飞机原始挂载信息:飞机在座位的变体容器节点里(该节点默认未激活,直接显隐看不到),
// 入场时临时挂到炮台下显示、结束/清理时按原样还原(父节点/层级/本地变换)
private Transform _enterPlaneOrigParent;
private int _enterPlaneOrigSibling;
private Vector3 _enterPlaneOrigLocalPos;
private Quaternion _enterPlaneOrigLocalRot;
private Vector3 _enterPlaneOrigLocalScale;
/// <summary> /// <summary>
/// XJMH 进房入场动画(移植原版 Battery:EnterAction 的非立即分支,本地玩家入座时调用一次): /// XJMH 进房入场动画(移植原版 Battery:EnterAction 的非立即分支,本地玩家入座时调用一次):
@@ -331,15 +341,17 @@ public class FlyTurretData : TurretData
_enterPlane = FindPlaneSkeletonRect(); _enterPlane = FindPlaneSkeletonRect();
if (_enterPlane == null) if (_enterPlane == null)
{ {
Debug.LogWarning($"[XJMH入场] {name} 未找到飞机节点(名字含 feiji),只播炮台出现动画"); Debug.LogWarning($"[XJMH入场] {name} 未找到飞机节点(炮台/座位子树内名字含 feiji),只播炮台出现动画");
PlayTurretOutAnim(); PlayTurretOutAnim();
_enterRoutine = null; _enterRoutine = null;
yield break; yield break;
} }
SkeletonGraphic planeSg = _enterPlane.GetComponent<SkeletonGraphic>(); _enterPlaneSg = _enterPlane.GetComponent<SkeletonGraphic>();
_enterPlaneHome = _enterPlane.anchoredPosition;
Vector2 home = _enterPlaneHome; // ⭐ 飞机临时挂到炮台下并保持停靠位(原挂载点=座位下的变体容器节点,默认未激活,不挂过来显示不了)
AttachPlaneForEnter();
Vector2 home = _enterPlane.anchoredPosition;
Vector2 start = home + new Vector2(0f, enterStartOffsetY); Vector2 start = home + new Vector2(0f, enterStartOffsetY);
Vector2 mid = home + new Vector2(0f, enterStartOffsetY * 0.5f); Vector2 mid = home + new Vector2(0f, enterStartOffsetY * 0.5f);
@@ -347,13 +359,20 @@ public class FlyTurretData : TurretData
// (PW_Battery.txt:EnterAction → bottomSkeleton.AnimationState:SetAnimation(0,"out",false)) // (PW_Battery.txt:EnterAction → bottomSkeleton.AnimationState:SetAnimation(0,"out",false))
PlayContainerOutAnim(); PlayContainerOutAnim();
// 原版:入场时炮台本体隐藏、飞机出现(飞机从下方升上来,"变"回炮台) // 原版:入场时炮台本体隐藏、飞机出现(飞机从下方升上来,"变"回炮台);Board(分板)一并隐藏
if (skeletonAnimation != null) if (skeletonAnimation != null)
skeletonAnimation.gameObject.SetActive(false); skeletonAnimation.gameObject.SetActive(false);
Transform board = transform.Find("Board");
if (board != null) { board.gameObject.SetActive(false); _enterBoardHidden = true; }
_enterPlane.gameObject.SetActive(true); _enterPlane.gameObject.SetActive(true);
_enterPlane.anchoredPosition = start; _enterPlane.anchoredPosition = start;
if (planeSg != null && planeSg.AnimationState != null) if (_enterPlaneSg != null && _enterPlaneSg.AnimationState != null)
planeSg.AnimationState.ClearTrack(0); // 清残留(对象池/重复入场) {
// 原版飞机常驻飞行循环(PlaneFlyAnim:"stand01" 循环);清残留(对象池/重复入场)后先播它
_enterPlaneSg.AnimationState.ClearTrack(0);
if (HasSpineAnim(_enterPlaneSg, "stand01"))
_enterPlaneSg.AnimationState.SetAnimation(0, "stand01", true);
}
// 第一段:升到中途位(原版 EInQuart) // 第一段:升到中途位(原版 EInQuart)
yield return RiseTo(_enterPlane, start, mid, enterRiseTime, true); yield return RiseTo(_enterPlane, start, mid, enterRiseTime, true);
@@ -362,19 +381,21 @@ public class FlyTurretData : TurretData
// 第二段:升到停靠位(原版 EOutQuart) // 第二段:升到停靠位(原版 EOutQuart)
yield return RiseTo(_enterPlane, mid, home, enterBackRiseTime, false); yield return RiseTo(_enterPlane, mid, home, enterBackRiseTime, false);
// PlaneBack 音效 + 飞机回位动画(原版 PlaneBack → PlaneBackAnim) // PlaneBack 音效 + 飞机回位动画(原版 PlaneBack → PlaneBackAnim:"back")
if (enterBackAudioID > 0 && AudioManager.Instance != null) if (enterBackAudioID > 0 && AudioManager.Instance != null)
AudioManager.Instance.PlayerFX(enterBackAudioID); AudioManager.Instance.PlayerFX(enterBackAudioID);
if (planeSg != null && planeSg.AnimationState != null) if (_enterPlaneSg != null && _enterPlaneSg.AnimationState != null && HasSpineAnim(_enterPlaneSg, "back"))
planeSg.AnimationState.SetAnimation(0, "back", false); _enterPlaneSg.AnimationState.SetAnimation(0, "back", false);
// 原版:back 动画约 1 秒后飞机隐藏、炮台出现(ShowGun) // 原版:back 动画约 1 秒后飞机隐藏、炮台出现(ShowGun → ShowBoard)
if (enterBackHoldTime > 0f) yield return new WaitForSeconds(enterBackHoldTime); if (enterBackHoldTime > 0f) yield return new WaitForSeconds(enterBackHoldTime);
_enterPlane.gameObject.SetActive(false); DetachPlaneAfterEnter(); // 飞机隐藏 + 还原父节点/本地变换
_enterPlane.anchoredPosition = home;
PlayTurretOutAnim();
_enterPlane = null; _enterPlane = null;
_enterPlaneSg = null;
PlayTurretOutAnim();
if (board != null) board.gameObject.SetActive(true);
_enterBoardHidden = false;
_enterRoutine = null; _enterRoutine = null;
} }
@@ -409,40 +430,149 @@ public class FlyTurretData : TurretData
} }
/// <summary> /// <summary>
/// 容器(底座/炮台外壳)出场动画:XJMH 炮台容器自身的 Spine 播 "out"(容器动画为 close/open/out)。 /// 容器(底座/炮台外壳)出场动画:容器 Spine 播 "out"(容器动画为 close/open/out)。
/// 对应原版 EnterAction 第 6 步 bottomSkeleton "out";容器上没有该动画时跳过、不报错。 /// 对应原版 EnterAction 第 6 步 bottomSkeleton "out"(battery/Bottom 上的骨架);没有该动画时跳过、不报错。
/// </summary> /// </summary>
private void PlayContainerOutAnim() private void PlayContainerOutAnim()
{ {
var shell = GetComponent<SkeletonGraphic>(); var shell = FindContainerSkeleton();
if (shell == null || shell.AnimationState == null) return; if (shell == null || shell.AnimationState == null) return;
if (shell.Skeleton != null && shell.Skeleton.Data != null if (!HasSpineAnim(shell, "out")) return; // 没有 out 动画:跳过
&& shell.Skeleton.Data.FindAnimation("out") == null) return; // 没有 out 动画:跳过
shell.AnimationState.SetAnimation(0, "out", false); shell.AnimationState.SetAnimation(0, "out", false);
shell.Update(0.1f); shell.Update(0.1f);
} }
/// <summary>找飞机节点:名字含 "feiji" 的 SkeletonGraphic(四种炮台各配一架:lvptfeiji/lanptfeiji/huangjinfeiji/vipfeiji01)</summary> /// <summary>
private RectTransform FindPlaneSkeletonRect() /// 找容器(底座外壳)骨架:① 炮台根节点自带(容器节点布局);
/// ② "Bottom" 子节点(原版 PW_Battery 结构,容器骨架在 Bottom 上,根节点没有);
/// ③ 兜底:子树里带 "out" 动画、且不是炮口本体/飞机的骨架。
/// </summary>
private SkeletonGraphic FindContainerSkeleton()
{ {
var self = GetComponent<SkeletonGraphic>();
if (self != null && self != skeletonAnimation && HasSpineAnim(self, "out")) return self;
Transform bottom = transform.Find("Bottom");
if (bottom != null)
{
var sg = bottom.GetComponent<SkeletonGraphic>();
if (sg != null && sg != skeletonAnimation) return sg;
}
foreach (var sg in GetComponentsInChildren<SkeletonGraphic>(true)) foreach (var sg in GetComponentsInChildren<SkeletonGraphic>(true))
{ {
if (sg == null) continue; if (sg == null || sg == skeletonAnimation) continue;
if (sg.gameObject.name.ToLowerInvariant().Contains("feiji")) if (sg.gameObject.name.ToLowerInvariant().Contains("feiji")) continue; // 飞机不算容器
return sg.rectTransform; if (HasSpineAnim(sg, "out")) return sg;
} }
return null; return null;
} }
/// <summary>入场动画清理:停协程 + 复位(飞机隐藏回停靠位、炮台本体恢复显示),禁用/回收不残留</summary> /// <summary>骨架数据里是否有该动画(SkeletonGraphic 已初始化才有效)</summary>
private static bool HasSpineAnim(SkeletonGraphic sg, string animName)
{
var data = sg != null && sg.Skeleton != null ? sg.Skeleton.Data : null;
return data != null && data.FindAnimation(animName) != null;
}
/// <summary>
/// 找飞机骨架:① 炮台子树(飞机挂在炮台下的布局);
/// ② 座位子树(当前 XJMH 布局:飞机与炮台平级、挂在座位的变体容器节点里,
/// 如 lvptfeiji/lanptfeiji/huangjinfeiji/vipfeiji01)——先按当前炮台等级挑对应飞机,挑不到用座位下任意飞机兜底。
/// </summary>
private RectTransform FindPlaneSkeletonRect()
{
var plane = FindPlaneSkeletonUnder(transform, null);
if (plane != null) return plane;
var sit = GetComponentInParent<SitPosData>();
if (sit == null) return null;
return FindPlaneSkeletonUnder(sit.transform, GetPlaneKeyword());
}
/// <summary>在 root 子树里找名字含 "feiji" 的 SkeletonGraphic;keyword 非空时优先匹配(如 lvpt)</summary>
private static RectTransform FindPlaneSkeletonUnder(Transform root, string keyword)
{
RectTransform any = null;
foreach (var sg in root.GetComponentsInChildren<SkeletonGraphic>(true))
{
if (sg == null) continue;
string n = sg.gameObject.name.ToLowerInvariant();
if (!n.Contains("feiji")) continue;
if (string.IsNullOrEmpty(keyword) || n.Contains(keyword)) return sg.rectTransform;
if (any == null) any = sg.rectTransform;
}
return any;
}
/// <summary>当前炮台等级 → 座位内飞机名关键字(原版 PW_Plane_1~4 = 绿/蓝/金/VIP 机)</summary>
private string GetPlaneKeyword()
{
switch (ParseTurretLevel())
{
case 1: return "lvpt";
case 2: return "lanpt";
case 3: return "huangjin";
case 4: return "vip";
default: return null;
}
}
/// <summary>炮台等级:优先 turretID(变体容器炮台配了 1~4),否则从名字里取数字(PW_Battery_2 → 2)</summary>
private int ParseTurretLevel()
{
if (!string.IsNullOrEmpty(turretID) && int.TryParse(turretID.Trim(), out int id) && id > 0)
return id;
foreach (char c in name)
if (char.IsDigit(c)) return c - '0';
return 0;
}
/// <summary>入场开始:飞机临时挂到炮台下(保留世界位置/旋转/缩放)——原挂载点(座位下的变体容器节点)默认未激活,直接显隐看不到</summary>
private void AttachPlaneForEnter()
{
_enterPlaneOrigParent = _enterPlane.parent;
_enterPlaneOrigSibling = _enterPlane.GetSiblingIndex();
_enterPlaneOrigLocalPos = _enterPlane.localPosition;
_enterPlaneOrigLocalRot = _enterPlane.localRotation;
_enterPlaneOrigLocalScale = _enterPlane.localScale;
if (_enterPlane.parent != transform)
_enterPlane.SetParent(transform, true); // true=保留世界变换,停靠位不跳
}
/// <summary>入场结束/清理:飞机隐藏并还原父节点与本地变换,不残留运行时改动</summary>
private void DetachPlaneAfterEnter()
{
if (_enterPlane == null) return;
_enterPlane.gameObject.SetActive(false);
if (_enterPlaneOrigParent != null && _enterPlane.parent != _enterPlaneOrigParent)
{
_enterPlane.SetParent(_enterPlaneOrigParent, false);
_enterPlane.SetSiblingIndex(_enterPlaneOrigSibling);
}
_enterPlane.localPosition = _enterPlaneOrigLocalPos;
_enterPlane.localRotation = _enterPlaneOrigLocalRot;
_enterPlane.localScale = _enterPlaneOrigLocalScale;
}
/// <summary>入场动画清理:停协程 + 飞机隐藏并还原挂载 + Board/炮台本体恢复显示,禁用/回收不残留</summary>
private void CleanupEnterAction() private void CleanupEnterAction()
{ {
if (_enterRoutine != null) { StopCoroutine(_enterRoutine); _enterRoutine = null; } if (_enterRoutine != null) { StopCoroutine(_enterRoutine); _enterRoutine = null; }
if (_enterPlane != null) if (_enterPlane != null)
{ {
_enterPlane.anchoredPosition = _enterPlaneHome; DetachPlaneAfterEnter();
_enterPlane.gameObject.SetActive(false);
_enterPlane = null; _enterPlane = null;
_enterPlaneSg = null;
}
// 入场中途被打断:恢复被本类暂时隐藏的 Board(只恢复自己隐藏的,不动其他逻辑的显隐)
if (_enterBoardHidden)
{
Transform board = transform.Find("Board");
if (board != null) board.gameObject.SetActive(true);
_enterBoardHidden = false;
} }
if (skeletonAnimation != null && !skeletonAnimation.gameObject.activeSelf) if (skeletonAnimation != null && !skeletonAnimation.gameObject.activeSelf)
skeletonAnimation.gameObject.SetActive(true); skeletonAnimation.gameObject.SetActive(true);
File diff suppressed because it is too large Load Diff