From 8fdf0fd052c148b02a8a5e4f21c043b4d6cdd5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A3=AE2003?= <2384017988@qq.com> Date: Tue, 18 Aug 2026 18:06:30 +0800 Subject: [PATCH] 1 --- .../XJMH/Boss/JiXieXie/PW_Enemy_3000.prefab | 2 +- .../Boss/XingJiXunHang/PW_Enemy_4000.prefab | 31 +++ .../Boss/XingJiXunHang/XingJiXunHangEvent.cs | 161 +++++++++++++-- .../Boss/XingJiXunHang/XingJiXunHang_BOSS.cs | 191 +++++++++++++++++- .../XingJiXunHang/dieFXPrefabAwardTmp.prefab | 5 +- 5 files changed, 373 insertions(+), 17 deletions(-) diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/JiXieXie/PW_Enemy_3000.prefab b/Assets/MyGame/aa/Game/XJMH/Boss/JiXieXie/PW_Enemy_3000.prefab index ed0b377d7..c5462d105 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/JiXieXie/PW_Enemy_3000.prefab +++ b/Assets/MyGame/aa/Game/XJMH/Boss/JiXieXie/PW_Enemy_3000.prefab @@ -122,7 +122,7 @@ MonoBehaviour: cachedCamera: {fileID: 0} cachedUirootRect: {fileID: 0} skeleton: {fileID: 0} - isSpine: 1 + isSpine: 0 fishTypeID: 12028 currState: 0 HP: 5 diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/PW_Enemy_4000.prefab b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/PW_Enemy_4000.prefab index 5e6d67ed4..877f09080 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/PW_Enemy_4000.prefab +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/PW_Enemy_4000.prefab @@ -8,10 +8,26 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 1146886045327190, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1622780724854902, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} - target: {fileID: 1658730911317380, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} propertyPath: m_Name value: PW_Enemy_4000 objectReference: {fileID: 0} + - target: {fileID: 1707060374769447, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1981398447280843, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} - target: {fileID: 4231307354823747, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} propertyPath: m_LocalPosition.x value: 0 @@ -52,6 +68,16 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: -0 objectReference: {fileID: 0} + - target: {fileID: 199488493079174609, guid: 44623ca91d5f59049b506c55c76f2aef, + type: 3} + propertyPath: m_Materials.Array.size + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 199656832037048821, guid: 44623ca91d5f59049b506c55c76f2aef, + type: 3} + propertyPath: m_Materials.Array.size + value: 1 + objectReference: {fileID: 0} m_RemovedComponents: - {fileID: 7031818894128611810, guid: 44623ca91d5f59049b506c55c76f2aef, type: 3} m_RemovedGameObjects: [] @@ -149,5 +175,10 @@ MonoBehaviour: nonFinalDeathBjEndUI: {fileID: -382508373279050920, guid: 75a52b8c1537cad49b3d521483fe134e, type: 3} resumeMoveDelay: 2 + nonFinalDeathAnimationName: stand02 + normalAnimationName: stand01 + skeletonChildName: + hittingPath: body/bone/hitting + hittingDuration: 2 useServerParam: 1 maxDeathCount: 2 diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHangEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHangEvent.cs index c1fa42354..222ede81e 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHangEvent.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHangEvent.cs @@ -178,6 +178,9 @@ public class XingJiXunHangEvent : BJEventBase [Tooltip("4条激光伸展到最长位置的耗时(秒)")] public float laserExpandSpeed = 0.6f; + [Tooltip("光子激光结束后等待时长(秒),然后直接隐藏 Prop(默认1)")] + public float symmetraPropHideDelay = 1f; + [Header("光子 - 电网扫动杀鱼")] [Tooltip("电网(Prop整体)上下扫动幅度(世界单位)")] public float netSweepAmplitude = 5f; @@ -202,9 +205,9 @@ public class XingJiXunHangEvent : BJEventBase public string[] gammaLaserNames = { "laser1", "laser2", "laser3", "laser4" }; [Tooltip("射线显示后到开始旋转的等待(秒,默认1)")] public float gammaRotateDelay = 1f; - [Tooltip("总旋转角度(度,默认80°)")] - public float gammaRotateAngle = 80f; - [Tooltip("转到该角度后激光开始缩短(度,默认45°)")] + [Tooltip("总旋转角度(度,默认90°,转完为止)")] + public float gammaRotateAngle = 90f; + [Tooltip("转到该角度后激光开始一点一点缩短(度,默认45°)")] public float gammaShrinkStartAngle = 45f; [Tooltip("旋转速度(度/秒,正=逆时针)")] public float gammaRotateSpeed = 45f; @@ -271,6 +274,12 @@ public class XingJiXunHangEvent : BJEventBase /// 本局电网已炸的鱼 guid(防止扫动中重复炸同一鱼) private readonly HashSet _netKilledFish = new HashSet(); + /// Boss 分数面板 TMP(挂在独立 UI 层,Boss 删除后仍有效) + private TMPro.TextMeshProUGUI _bossScoreTmp; + + /// 本局杀鱼累计加到 Boss 面板的分值 + private long _bossPanelScore = 0; + /// 爆奖过程中实例化的所有临时特效(die() 时统一销毁,防止残留) private readonly System.Collections.Generic.List _spawnedEffects = new System.Collections.Generic.List(); @@ -294,6 +303,9 @@ public class XingJiXunHangEvent : BJEventBase scoreCount = bjCount; totalBJCount = bjCount; + // ⭐ 星际巡航不需要 ScoreNumScroll(Clone) 加分数字滚动特效(杀鱼分已加 Boss 面板) + showAddScoreFX = false; + // 解析武器 ID ParseWeaponId(); @@ -324,6 +336,8 @@ public class XingJiXunHangEvent : BJEventBase bossCtrl = null; diePos = Vector3.zero; _netKilledFish.Clear(); + _bossScoreTmp = null; + _bossPanelScore = 0; // ⭐ 对象池复用:清理上次残留的临时特效 for (int i = 0; i < _spawnedEffects.Count; i++) @@ -383,7 +397,7 @@ public class XingJiXunHangEvent : BJEventBase /// 根据武器 ID 选择对应的预制体和标签 private void SelectWeaponPrefabs() { - _weaponId = 8; + _weaponId = 7; switch (_weaponId) { case 0: @@ -842,10 +856,16 @@ public class XingJiXunHangEvent : BJEventBase // ⭐ 逐个杀:每只间隔 = 总时长/数量,整体约 1 秒 float interval = ironFistKillTotalTime / fishes.Count; - Vector3 sitPos = GetSeatPosition(); + Vector3 turretPos = GetSeatPosition(); // 金币飞向炮台 int killed = 0; foreach (var monster in fishes) { + // ⭐ 分数加满(=maxScore)后停止杀鱼 + if (BossScoreFull) + { + Debug.Log($"[XingJiXunHang] 铁拳: 面板分已达上限 {maxScore},停止杀鱼"); + break; + } if (monster == null) continue; if (!_netKilledFish.Add(monster.guid)) continue; @@ -853,7 +873,9 @@ public class XingJiXunHangEvent : BJEventBase { Amount = paoBei * monster.monsterData.fishTypeConfig.fishScore }; - CreateFishManager.Instance.Id_DieFish_FX(monster.guid, coinNum, sitPos, isLocal: isSelf); + // ⭐ 飞机死亡掉金币(飞向炮台),分数同时加到 Boss 面板(封顶 maxScore) + CreateFishManager.Instance.Id_DieFish_FX(monster.guid, coinNum, turretPos, isLocal: isSelf); + AddBossPanelScore(coinNum.Amount); killed++; Debug.Log($"[XingJiXunHang] 铁拳: 从近到远杀鱼[{killed}/{fishes.Count}] 距离={Vector2.Distance(monster.transform.position, center):0.00}"); yield return new WaitForSeconds(interval); @@ -959,7 +981,13 @@ public class XingJiXunHangEvent : BJEventBase yield return StartCoroutine(ElectricNetSweep(propObj, propL, propR)); } - yield return new WaitForSeconds(0.3f); + // ⭐ 激光结束:等 1 秒后直接隐藏 Prop(不再一直显示到爆奖结束才回收) + yield return new WaitForSeconds(symmetraPropHideDelay); + if (propObj != null) + { + propObj.SetActive(false); + Debug.Log($"[XingJiXunHang] 光子: 激光结束等待 {symmetraPropHideDelay}s 后隐藏 Prop"); + } } /// @@ -1010,8 +1038,9 @@ public class XingJiXunHangEvent : BJEventBase } /// - /// 电网扫动:Prop 整体上下移动(幅度 netSweepAmplitude,来回 netSweepCycles 次), + /// 电网扫动:Prop 整体上下移动(幅度 netSweepAmplitude,最多 netSweepCycles 次), /// 扫动过程中每帧检测 PropL~PropR 之间的矩形区域,碰到普通鱼 → 爆炸(Id_DieFish_FX)。 + /// ⭐ 不需要一直按设定的圈数移动:面板分加满(=maxScore)后提前停止扫动。 /// private IEnumerator ElectricNetSweep(GameObject propObj, Transform propL, Transform propR) { @@ -1020,14 +1049,21 @@ public class XingJiXunHangEvent : BJEventBase Vector3 basePos = propObj.transform.position; for (int i = 0; i < netSweepCycles; i++) { + // ⭐ 面板分加满:提前停止扫动(不需要一直按圈数移动) + if (BossScoreFull) + { + Debug.Log($"[XingJiXunHang] 光子: 面板分已达上限 {maxScore},提前停止电网扫动"); + break; + } // 上扫 yield return StartCoroutine(SweepSegment(propObj, propL, propR, basePos + Vector3.up * netSweepAmplitude)); + if (BossScoreFull) break; // 下扫 yield return StartCoroutine(SweepSegment(propObj, propL, propR, basePos - Vector3.up * netSweepAmplitude)); } // 回原位 yield return StartCoroutine(SweepSegment(propObj, propL, propR, basePos)); - Debug.Log($"[XingJiXunHang] 光子: 电网扫动完成 cycles={netSweepCycles} 炸鱼数={_netKilledFish.Count}"); + Debug.Log($"[XingJiXunHang] 光子: 电网扫动结束(计划{netSweepCycles}圈)炸鱼数={_netKilledFish.Count}"); } /// 电网从当前位置移动到 dest(逐帧插值 + 途中杀鱼) @@ -1045,10 +1081,12 @@ public class XingJiXunHangEvent : BJEventBase propObj.transform.position = Vector3.Lerp(start, dest, t); if (netKillFish) KillFishInNet(propL, propR); + // ⭐ 分数加满:本段提前结束 + if (BossScoreFull) break; yield return null; } propObj.transform.position = dest; - if (netKillFish) + if (netKillFish && !BossScoreFull) KillFishInNet(propL, propR); } @@ -1075,10 +1113,16 @@ public class XingJiXunHangEvent : BJEventBase Collider2D[] hits = Physics2D.OverlapAreaAll(min, max, netKillLayer); if (hits == null || hits.Length == 0) return; - Vector3 sitPos = GetSeatPosition(); + Vector3 turretPos = GetSeatPosition(); // 金币飞向炮台 int killed = 0; foreach (var hit in hits) { + // ⭐ 分数加满(=maxScore)后停止杀鱼 + if (BossScoreFull) + { + Debug.Log($"[XingJiXunHang] 电网: 面板分已达上限 {maxScore},停止杀鱼"); + break; + } if (hit == null || !hit.CompareTag("Fish")) continue; var monster = hit.GetComponentInParent(); if (monster == null) continue; @@ -1089,7 +1133,9 @@ public class XingJiXunHangEvent : BJEventBase { Amount = paoBei * monster.monsterData.fishTypeConfig.fishScore }; - CreateFishManager.Instance.Id_DieFish_FX(monster.guid, coinNum, sitPos, isLocal: isSelf); + // ⭐ 飞机死亡掉金币(飞向炮台),分数同时加到 Boss 面板(封顶 maxScore) + CreateFishManager.Instance.Id_DieFish_FX(monster.guid, coinNum, turretPos, isLocal: isSelf); + AddBossPanelScore(coinNum.Amount); killed++; } if (killed > 0) @@ -1209,6 +1255,17 @@ public class XingJiXunHangEvent : BJEventBase // 终点:激光缩到 0 长度(隐藏) UpdateGammaLaserEndpoints(lasers, propObj.transform.position, 0f); Debug.Log($"[XingJiXunHang] 伽马风暴: 旋转完成 {rotated:0.#}°(45°后激光缩短至消失)炸鱼 {killCount} 条"); + + // ⭐ 分不够就直接补齐到 maxScore(旋转杀鱼没杀满时,面板补满) + if (!BossScoreFull) + { + long need = maxScore - _bossPanelScore; + if (need > 0) + { + AddBossPanelScore(need); + Debug.Log($"[XingJiXunHang] 伽马风暴: 分不够,直接补齐 {need} → {_bossPanelScore}"); + } + } } /// @@ -1282,7 +1339,7 @@ public class XingJiXunHangEvent : BJEventBase return; } - Vector3 sitPos = GetSeatPosition(); + Vector3 turretPos = GetSeatPosition(); // 金币飞向炮台 foreach (var laser in lasers) { if (laser == null) continue; @@ -1299,6 +1356,12 @@ public class XingJiXunHangEvent : BJEventBase foreach (var hit in hits) { + // ⭐ 分数加满(=maxScore)后停止杀鱼 + if (BossScoreFull) + { + Debug.Log($"[XingJiXunHang] 伽马射线: 面板分已达上限 {maxScore},停止杀鱼"); + return; + } if (hit.collider == null || !hit.collider.CompareTag("Fish")) continue; var monster = hit.collider.GetComponentInParent(); if (monster == null) continue; @@ -1309,7 +1372,9 @@ public class XingJiXunHangEvent : BJEventBase { Amount = paoBei * monster.monsterData.fishTypeConfig.fishScore }; - CreateFishManager.Instance.Id_DieFish_FX(monster.guid, coinNum, sitPos, isLocal: isSelf); + // ⭐ 飞机死亡掉金币(飞向炮台),分数同时加到 Boss 面板(封顶 maxScore) + CreateFishManager.Instance.Id_DieFish_FX(monster.guid, coinNum, turretPos, isLocal: isSelf); + AddBossPanelScore(coinNum.Amount); killCount++; } } @@ -1363,6 +1428,55 @@ public class XingJiXunHangEvent : BJEventBase // ==================== 辅助方法 ==================== + /// 每死亡一个飞机,就往 Boss 分数面板上加一个分(面板独立于 Boss 本体,删除后仍有效) + private void AddBossPanelScore(long amount) + { + if (amount <= 0) return; + + // ⭐ 面板加分不能超过金币上限 maxScore(封顶) + long newScore = _bossPanelScore + amount; + if (newScore > maxScore) + newScore = maxScore; + if (newScore == _bossPanelScore) return; // 已封顶,无变化 + + _bossPanelScore = newScore; + EnsureBossScoreTmp(); + if (_bossScoreTmp != null) + { + _bossScoreTmp.text = _bossPanelScore.ToString(); + Debug.Log($"[XingJiXunHang] Boss分数面板 +{amount} = {_bossPanelScore}(上限{maxScore})"); + } + } + + /// 面板分是否已加满(= maxScore 后停止杀鱼) + private bool BossScoreFull => _bossPanelScore >= maxScore; + + /// 确保 Boss 分数面板 TMP 可用(优先用 bossCtrl 已创建的,否则手动创建) + private void EnsureBossScoreTmp() + { + if (_bossScoreTmp != null) return; + + // 1. 从 bossCtrl 拿(Boss 删除前已缓存的面板引用) + if (bossCtrl != null && bossCtrl.tMP_CurrBossScore != null) + { + _bossScoreTmp = bossCtrl.tMP_CurrBossScore; + return; + } + + // 2. 手动创建分数面板(同 MonsterControl_BossBase.EnsureScorePanel 逻辑) + var prefab = CreateFishManager.Instance != null + ? CreateFishManager.Instance.dieFXPrefabAwardTmp : null; + var parent = CreateFishManager.Instance != null && CreateFishManager.Instance.currGameType != null + ? CreateFishManager.Instance.currGameType.subPanelParent : null; + if (prefab == null || parent == null) return; + + var board = Instantiate(prefab, parent); + // ⭐ 加分面板位置放在座位上方才是正常的 + board.transform.position = GetSeatPosition() + Vector3.up * 150f; + + _bossScoreTmp = board.transform.GetChild(0).GetComponent(); + } + /// /// 缓存 UI 层父节点 + Canvas: /// 父节点 = currGameType.subPanelParent.parent(与爆奖预制体同层,随 UI 卸载自动清理) @@ -1548,6 +1662,25 @@ public class XingJiXunHangEvent : BJEventBase EffectPool.Instance.Return(gameObject); } + /// + /// 加分完成:先走基类(显示 BJEndUI + 加分 + 收尾), + /// 然后删除/回收手动创建的 Boss 分数面板(_bossScoreTmp)。 + /// + protected override void OnScoreEnd() + { + base.OnScoreEnd(); // ⭐ 弹出 BJEndUI + + // ⭐ 弹出 BJEndUI 时回收/删除手动创建的 Boss 分数面板 + if (_bossScoreTmp != null) + { + var board = _bossScoreTmp.transform.parent; + if (board != null) + Destroy(board.gameObject); + _bossScoreTmp = null; + Debug.Log("[XingJiXunHang] 弹出 BJEndUI:Boss 分数面板已删除"); + } + } + private void OnDestroy() { StopAllCoroutines(); diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs index 8d7741cb3..709bc4f32 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs @@ -1,5 +1,6 @@ using Assets.MyGame.Scripts.Net.WebResponses; using Newtonsoft.Json.Linq; +using Spine.Unity; using System; using System.Collections; using UnityEngine; @@ -29,6 +30,23 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase [Tooltip("非最终死亡后,Boss 恢复游动的延迟(秒)")] public float resumeMoveDelay = 2f; + [Header("星际巡航 - 非最终死亡动画(animId=1)")] + [Tooltip("不死时播放的 Spine 动画名(stand02 = 第一种不死亡爆奖动画)")] + public string nonFinalDeathAnimationName = "stand02"; + + [Tooltip("正常默认动画名(stand01,不死动画播放完恢复游动时切回)")] + public string normalAnimationName = "stand01"; + + [Tooltip("SkeletonAnimation 所在子对象名(留空=自动 GetComponentInChildren 查找)")] + public string skeletonChildName = ""; + + [Header("星际巡航 - Hitting 特效")] + [Tooltip("Hitting 特效子对象路径(相对 Boss 根,如 body/bone/hitting)")] + public string hittingPath = "body/bone/hitting"; + + [Tooltip("Hitting 特效激活持续时间(秒,默认2)")] + public float hittingDuration = 2f; + [Header("星际巡航 - 服务端参数解析")] [Tooltip("是否从 param 解析 isKill(关闭则用 maxDeathCount 客户端兜底判定)")] public bool useServerParam = true; @@ -67,6 +85,9 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase /// 爆奖事件是否已 Init(决定特效实例由谁回收) private bool _awardInitCalled = false; + /// 正在运行的 Hitting 特效协程(同一时间只允许一个,防连续触发冲突) + private Coroutine _hittingRoutine = null; + // ==================== Unity 生命周期 ==================== public override void OnEnable() @@ -79,7 +100,33 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase _removed = false; _diePosCached = false; _awardInitCalled = false; + _hittingRoutine = null; currEvent = null; + + // ⭐ 恢复被修改过的激活状态(对象池复用:Hitting 特效强制恢复初始关闭) + ResetHittingState(); + } + + /// 恢复 Hitting 特效的初始激活状态(关闭) + private void ResetHittingState() + { + // 停掉残留的 Hitting 协程 + if (_hittingRoutine != null) + { + StopCoroutine(_hittingRoutine); + _hittingRoutine = null; + } + + Transform hitting = null; + if (!string.IsNullOrEmpty(hittingPath)) + { + hitting = transform.Find(hittingPath); + if (hitting == null) + hitting = FindChildPathIgnoreCase(transform, hittingPath); + } + + if (hitting != null) + hitting.gameObject.SetActive(false); } // ==================== 死亡逻辑 ==================== @@ -142,13 +189,21 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase // ==================== 非最终死亡 ==================== - /// 非最终死亡:显示 BJEndUI,Boss 保留,等待下次击杀 + /// 非最终死亡:显示 BJEndUI + 播放不死动画,Boss 保留,等待下次击杀 private void NonFinalDeath(RoomKillNotice obj, int beishu) { _cachedKillNotice = obj; Debug.Log($"[XingJiXunHang] 非最终死亡:显示 BJEndUI,Boss 保留"); + // ⭐ 播放不死动画(SkeletonAnimation,从子对象获取) + PlayNonFinalDeathAnimation(); + + // ⭐ 播放 Hitting 特效:只激活一个协程(连续触发先停旧的,防止特效状态错乱) + if (_hittingRoutine != null) + StopCoroutine(_hittingRoutine); + _hittingRoutine = StartCoroutine(PlayHittingEffect()); + // 显示 BJEndUI(倍数+分数) ShowNonFinalDeathBjEndUI(obj, beishu); @@ -177,6 +232,140 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase isMove = true; Debug.Log("[XingJiXunHang] 非最终死亡后恢复游动"); } + + // ⭐ 不死动画(stand02)播完,切回正常默认动画(stand01) + PlaySkeletonAnimation(normalAnimationName); + } + + /// 获取 SkeletonAnimation(指定子对象或递归查找)并播放指定动画;动画不存在时回退 fallbackName + private void PlaySkeletonAnimation(string animationName, string fallbackName = null) + { + if (string.IsNullOrEmpty(animationName)) return; + + SkeletonAnimation sa = null; + + // 1. 指定子对象名 → 直接找该子对象上的组件 + if (!string.IsNullOrEmpty(skeletonChildName)) + { + Transform child = transform.Find(skeletonChildName); + if (child != null) + { + sa = child.GetComponent(); + if (sa == null) + sa = child.GetComponentInChildren(true); + } + } + + // 2. 递归查找:⭐ 优先选"包含目标动画"的 SkeletonAnimation(避免选错骨架) + if (sa == null) + { + var all = GetComponentsInChildren(true); + Debug.Log($"[XingJiXunHang] 找到 {all.Length} 个 SkeletonAnimation,目标动画={animationName}"); + foreach (var s in all) + { + // Skeleton.data 是 protected,改用 SkeletonDataAsset 公共 API + var sd = s.SkeletonDataAsset != null ? s.SkeletonDataAsset.GetSkeletonData(false) : null; + if (sd != null && sd.FindAnimation(animationName) != null) + { + sa = s; + Debug.Log($"[XingJiXunHang] 选择包含动画 {animationName} 的骨架: {s.gameObject.name}"); + break; + } + } + if (sa == null && all.Length > 0) + { + sa = all[0]; + Debug.LogWarning($"[XingJiXunHang] 没有骨架包含动画 {animationName},用第一个 {sa.gameObject.name}"); + } + } + + if (sa == null) + { + Debug.LogWarning($"[XingJiXunHang] 找不到 SkeletonAnimation(子对象={skeletonChildName}),跳过动画 {animationName}"); + return; + } + + // ⭐ 目标动画在骨架里不存在 → 回退 fallbackName(防预制体存旧动画名如 "hit") + var data = sa.SkeletonDataAsset != null ? sa.SkeletonDataAsset.GetSkeletonData(false) : null; + if (data != null && data.FindAnimation(animationName) == null) + { + if (!string.IsNullOrEmpty(fallbackName) && data.FindAnimation(fallbackName) != null) + { + Debug.LogWarning($"[XingJiXunHang] 动画 {animationName} 不存在,回退 {fallbackName}"); + animationName = fallbackName; + } + else + { + var animNames = new System.Collections.Generic.List(); + foreach (var a in data.Animations) animNames.Add(a.Name); + Debug.LogWarning($"[XingJiXunHang] 骨架 {sa.gameObject.name} 可用动画: {string.Join(", ", animNames)}"); + } + } + + sa.AnimationName = animationName; + sa.timeScale = 1f; + Debug.Log($"[XingJiXunHang] 播放 Spine 动画: {animationName}(SkeletonAnimation on {sa.gameObject.name})"); + } + + /// 播放不死动画(stand02 = 第一种不死亡爆奖动画;Inspector 旧值找不到时回退 stand02) + private void PlayNonFinalDeathAnimation() + { + PlaySkeletonAnimation(nonFinalDeathAnimationName, "stand02"); + } + + /// + /// 播放 Hitting 特效:激活子对象(body/bone/hitting),等待 hittingDuration 秒后关闭。 + /// ⭐ transform.Find 大小写敏感,找不到时用大小写不敏感路径查找兜底(Body/bone/hitting)。 + /// + private IEnumerator PlayHittingEffect() + { + Transform hitting = null; + if (!string.IsNullOrEmpty(hittingPath)) + { + hitting = transform.Find(hittingPath); + if (hitting == null) + hitting = FindChildPathIgnoreCase(transform, hittingPath); + } + + if (hitting == null) + { + Debug.LogWarning($"[XingJiXunHang] 找不到 Hitting 特效子对象 {hittingPath},跳过"); + yield break; + } + + hitting.gameObject.SetActive(true); + Debug.Log($"[XingJiXunHang] Hitting 特效激活({hittingPath} → {hitting.gameObject.name})"); + + yield return new WaitForSeconds(hittingDuration); + + if (hitting != null) + hitting.gameObject.SetActive(false); + _hittingRoutine = null; // 协程结束,允许下一次触发 + Debug.Log($"[XingJiXunHang] Hitting 特效关闭({hittingDuration}s 后)"); + } + + /// 按路径逐级查找子对象(忽略大小写) + private Transform FindChildPathIgnoreCase(Transform root, string path) + { + if (root == null || string.IsNullOrEmpty(path)) return null; + + Transform cur = root; + string[] parts = path.Split('/'); + foreach (var p in parts) + { + Transform found = null; + for (int i = 0; i < cur.childCount; i++) + { + if (string.Equals(cur.GetChild(i).name, p, StringComparison.OrdinalIgnoreCase)) + { + found = cur.GetChild(i); + break; + } + } + if (found == null) return null; + cur = found; + } + return cur; } /// 非最终死亡:显示 BJEndUI diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/dieFXPrefabAwardTmp.prefab b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/dieFXPrefabAwardTmp.prefab index 11402bb53..6a72617a6 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/dieFXPrefabAwardTmp.prefab +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/dieFXPrefabAwardTmp.prefab @@ -45,7 +45,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: bjEndUI: {fileID: -382508373279050920, guid: 75a52b8c1537cad49b3d521483fe134e, type: 3} - useScorePanel: 1 + useScorePanel: 0 tMP_Score: {fileID: 0} scorePanelPrefab: {fileID: 0} currScore: 0 @@ -126,6 +126,8 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 64 ironFistKillFish: 1 + ironFistKillTotalTime: 1 + ironFistAwardDelay: 2 symmetraLockName: Lock symmetraPropLName: PropL symmetraPropRName: PropR @@ -137,6 +139,7 @@ MonoBehaviour: laser3Name: laser3 laser4Name: laser4 laserExpandSpeed: 0.6 + symmetraPropHideDelay: 1 netSweepAmplitude: 20 netSweepCycles: 3 netSweepSpeed: 3