1
This commit is contained in:
@@ -1,14 +1,34 @@
|
||||
using Assets.MyGame.Scripts.Net.WebResponses;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Spine.Unity;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 烈焰风暴 Boss(精简版:只根据服务端 param 判定死亡/未死亡)。
|
||||
/// 烈焰风暴 Boss(对齐 lua:pw_enemy/PW_FlameStrike.txt + pw_bullet/PW_BulletFlameStrike.txt)。
|
||||
///
|
||||
/// 本体结构(Art/XJMH/pw/pw_prefab/game/enemy/XJMHEnemy/PW_Enemy_115.prefab):
|
||||
/// root(PW_Enemy_115, isSpine=1) → Body → Bone → { Stand(待机特效) / Die(死亡特效) / Explosion(爆炸特效) }
|
||||
/// Wheel(轮盘,4 个子节点 = 火球弹发射点)
|
||||
/// Spine 动画名:stand01(待机) / stand02(受击死亡) —— 与 lua SetAnimation(1)/(2) 一致。
|
||||
///
|
||||
/// 表现流程(lua):
|
||||
/// OnCreate → ActiveCollider(true) + SetAnimation(1)(stand01 + 待机特效)
|
||||
/// 被击中(未死亡) → isSelf 播 PW_FlameStrike_Explosion;ShowEffect(Explosion) → 0.3s 播爆奖
|
||||
/// → 0.8s 关掉全部特效(回到待机特效)→ 恢复游动
|
||||
/// 被打死 → SetAnimation(2)(stand02 + 死亡特效);isSelf 播 Explosion/Die 两个音效
|
||||
/// · Free 子弹:ShowEffect(Explosion) → 0.3s 爆奖 → 0.8s 销毁本体
|
||||
/// · 普通子弹:等 1.8s(Timer)→ 从 Wheel 的 4 个子节点朝外生成火球弹
|
||||
/// (BulletType.FlameRound)→ 销毁本体
|
||||
/// 黑洞吸收 → 原版显式免疫(本项目黑洞只吸“普通鱼”,Boss 天然不受影响,无需处理)
|
||||
///
|
||||
/// param: { "isKill": bool, "beishu": int, "fishId": "...", "animId": int }
|
||||
/// animId==1 / isKill=false → 未死亡:炸一下 + bjEndUI,Boss 不消失,爆奖结束恢复游动
|
||||
/// animId>=2 / isKill=true → 死亡:炸一下 + bjEndUI,Boss 消失
|
||||
///
|
||||
/// 无死鱼、无红包、无中间过程。
|
||||
/// animId==1 / isKill=false → 未死亡(Boss 保留,爆奖结束恢复游动)
|
||||
/// animId>=2 / isKill=true → 死亡(Boss 消失)
|
||||
/// (可选)param.flameInfo = { originUID, ratio, sourceUIDList:[...] }:火球弹来源列表
|
||||
/// param.bulletType = 1(Free) 时走"免费子弹"分支
|
||||
/// </summary>
|
||||
public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
{
|
||||
@@ -16,22 +36,49 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
[Tooltip("是否从 param 解析 isKill/animId(关闭则每次死亡都按死亡处理)")]
|
||||
public bool useServerParam = true;
|
||||
|
||||
/// <summary>爆奖事件引用</summary>
|
||||
[Header("火球弹(lua BulletType.FlameRound,从 Wheel 子节点发射)")]
|
||||
[Tooltip("火球弹预制体(Assets/MyGame/aa/Game/XJMH/Prefabs/Bullit/PW_Bullet_FlameRound.prefab)")]
|
||||
public GameObject flameRoundBulletPrefab;
|
||||
[Tooltip("火球弹飞行速度(lua speed=30,按本项目世界比例可调)")]
|
||||
public float flameRoundSpeed = 30f;
|
||||
[Tooltip("火球弹存活时长(秒,兜底回收,防飞出屏外不回收)")]
|
||||
public float flameRoundLifeTime = 4f;
|
||||
[Tooltip("param 里没有 flameInfo 时的默认发射数量(最多 = Wheel 子节点数)")]
|
||||
public int flameRoundFallbackCount = 4;
|
||||
|
||||
[Header("时序(对齐 lua 硬编码值)")]
|
||||
[Tooltip("爆炸特效 → 播爆奖的延迟(lua 0.3s)")]
|
||||
public float explosionToRewardDelay = 0.3f;
|
||||
[Tooltip("未死亡:爆奖 → 关掉全部特效恢复待机的延迟(lua 0.8s)")]
|
||||
public float rewardToResetDelay = 0.8f;
|
||||
[Tooltip("死亡:爆炸 → 生成火球弹 + 销毁本体的延迟(lua Timer 1.8s)")]
|
||||
public float dieToFlameRoundDelay = 1.8f;
|
||||
|
||||
/// <summary>爆奖事件引用(死亡时赋值,供外部检查爆奖是否结束)</summary>
|
||||
[System.NonSerialized]
|
||||
public LieYanFengBaoEvent currEvent;
|
||||
|
||||
/// <summary>当前死亡次数(仅日志用)</summary>
|
||||
private int _deathCount = 0;
|
||||
// ---- 与 lua 对齐的常量 ----
|
||||
private const string AnimNormal = "stand01"; // lua SetAnimation(1)
|
||||
private const string AnimHit = "stand02"; // lua SetAnimation(2)
|
||||
private const int EffectStand = 1; // lua effectTab[1]
|
||||
private const int EffectDie = 2; // lua effectTab[2]
|
||||
private const int EffectExplosion = 3; // lua effectTab[3]
|
||||
private const string BonePath = "Body/Bone";
|
||||
private const string WheelName = "Wheel";
|
||||
private static readonly string[] EffectNodeNames = { "Stand", "Die", "Explosion" }; // 下标 0/1/2
|
||||
private const int BulletTypeFree = 1; // lua GC.Config.BulletType.Free
|
||||
|
||||
/// <summary>缓存死亡位置(删除 Boss 后 transform 不可靠)</summary>
|
||||
// ---- 运行时状态 ----
|
||||
private int _deathCount = 0;
|
||||
private Vector3 _diePos;
|
||||
private bool _diePosCached = false;
|
||||
|
||||
/// <summary>Boss 是否已从鱼列表回收(防重复回收)</summary>
|
||||
private bool _removed = false;
|
||||
|
||||
/// <summary>爆奖事件是否已 Init(决定特效实例由谁回收)</summary>
|
||||
private bool _awardInitCalled = false;
|
||||
private SkeletonAnimation _spine; // 预制体 skeleton 字段为空 → 运行时自动解析
|
||||
private readonly GameObject[] _effects = new GameObject[3];
|
||||
private Transform _wheel; // 轮盘(火球弹发射点父节点)
|
||||
private Coroutine _flowRoutine; // 表现流程协程(死亡/未死亡共用)
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
@@ -41,8 +88,83 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
_removed = false;
|
||||
_awardInitCalled = false;
|
||||
currEvent = null;
|
||||
_flowRoutine = null;
|
||||
|
||||
ResolveNodes();
|
||||
|
||||
// lua OnCreate:ActiveCollider(true) + SetAnimation(1)
|
||||
SetAnimation(EffectStand);
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
StopFlow();
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 节点解析 & 表现(对齐 lua SetAnimation / ShowEffect)
|
||||
// ================================================================
|
||||
|
||||
/// <summary>
|
||||
/// 解析本体节点:Bone 下三个特效(Stand/Die/Explosion)+ Wheel + SkeletonAnimation。
|
||||
/// ⭐ 预制体 PW_Enemy_115 的 skeleton 字段为空,这里自动 GetComponentInChildren 兜底。
|
||||
/// </summary>
|
||||
private void ResolveNodes()
|
||||
{
|
||||
Transform bone = FindByPath(BonePath);
|
||||
for (int i = 0; i < EffectNodeNames.Length; i++)
|
||||
{
|
||||
_effects[i] = FindEffectNode(bone, EffectNodeNames[i]);
|
||||
}
|
||||
|
||||
_wheel = FindChildRecursive(transform, WheelName);
|
||||
|
||||
if (_spine == null)
|
||||
_spine = GetComponentInChildren<SkeletonAnimation>(true);
|
||||
|
||||
if (bone == null)
|
||||
Debug.LogWarning($"[LieYanFengBao] 找不到 {BonePath},待机/死亡/爆炸特效无法切换");
|
||||
if (_wheel == null)
|
||||
Debug.LogWarning($"[LieYanFengBao] 找不到 {WheelName},死亡时无法生成火球弹");
|
||||
}
|
||||
|
||||
/// <summary>lua SetAnimation(type):切 Spine 动画(stand01/stand02,循环)+ ShowEffect(type)</summary>
|
||||
private void SetAnimation(int type)
|
||||
{
|
||||
PlaySpineSafe(type == EffectDie ? AnimHit : AnimNormal, true);
|
||||
ShowEffect(type);
|
||||
}
|
||||
|
||||
/// <summary>lua ShowEffect(type):只激活 effectTab[type],type=0 时全部关闭</summary>
|
||||
private void ShowEffect(int type)
|
||||
{
|
||||
for (int i = 0; i < _effects.Length; i++)
|
||||
{
|
||||
if (_effects[i] == null) continue;
|
||||
bool on = (i + 1) == type; // effectTab[1..3] ↔ _effects[0..2]
|
||||
if (_effects[i].activeSelf != on)
|
||||
_effects[i].SetActive(on);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>安全播放 Spine 动画(骨架/动画名缺失时静默跳过)</summary>
|
||||
private void PlaySpineSafe(string animName, bool loop)
|
||||
{
|
||||
if (_spine == null || string.IsNullOrEmpty(animName)) return;
|
||||
var data = _spine.SkeletonDataAsset != null ? _spine.SkeletonDataAsset.GetSkeletonData(false) : null;
|
||||
if (data == null || data.FindAnimation(animName) == null)
|
||||
{
|
||||
Debug.LogWarning($"[LieYanFengBao] Spine 动画 {animName} 不存在,跳过");
|
||||
return;
|
||||
}
|
||||
_spine.AnimationState.SetAnimation(0, animName, loop);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 死亡 / 被击(对齐 lua OnExplosion,两种分支)
|
||||
// ================================================================
|
||||
|
||||
public override void DieFish(RoomKillNotice obj = null)
|
||||
{
|
||||
_deathCount++;
|
||||
@@ -50,10 +172,11 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
// ===== 解析服务端 param:animId 优先于 isKill =====
|
||||
bool isKill;
|
||||
int beishu;
|
||||
JToken param = obj?.param;
|
||||
|
||||
if (useServerParam && obj?.param != null)
|
||||
if (useServerParam && param != null)
|
||||
{
|
||||
var p = BossKillParamParser.ParseMultiDeath(obj.param);
|
||||
var p = BossKillParamParser.ParseMultiDeath(param);
|
||||
if (p != null)
|
||||
{
|
||||
isKill = p.isKill;
|
||||
@@ -64,7 +187,6 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// param 解析失败:按死亡处理
|
||||
isKill = true;
|
||||
beishu = obj.beishu > 0 ? (int)obj.beishu : 1;
|
||||
Debug.LogWarning($"[LieYanFengBao] param 解析失败,按死亡处理 beishu={beishu}");
|
||||
@@ -72,37 +194,179 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// 老消息无 param:按死亡处理
|
||||
isKill = true;
|
||||
beishu = obj?.beishu > 0 ? (int)obj.beishu : 1;
|
||||
Debug.Log($"[LieYanFengBao] DieFish 第{_deathCount}次(无param,按死亡) beishu={beishu}");
|
||||
}
|
||||
|
||||
// 缓存死亡位置(供爆奖特效定位)
|
||||
// 缓存死亡位置(Boss 删除后 transform 不可靠)
|
||||
_diePos = transform.position;
|
||||
_diePosCached = true;
|
||||
|
||||
// 炸一下 + bjEndUI(爆奖特效初始化回调,死亡/未死亡都播)
|
||||
// 爆奖特效初始化回调(CreateFishManager 在死亡位置创建 effect_DieAward 后回调)
|
||||
action_effect_DieAward = (o) => InitAwardEffect(o, obj, beishu);
|
||||
|
||||
bool isSelfKill = obj != null && GameManager.Instance != null && obj.userId == GameManager.Instance.user.id;
|
||||
|
||||
if (isKill)
|
||||
{
|
||||
// ===== 死亡:Boss 消失 =====
|
||||
// ===== 死亡:死亡动画 + 死亡特效 + 音效 → 延迟生成火球弹 → 回收本体 =====
|
||||
isDieFish = true;
|
||||
if (obj != null)
|
||||
poolNum = (int)obj.gold;
|
||||
StartCoroutine(RemoveBossNextFrame());
|
||||
|
||||
SetAnimation(EffectDie);
|
||||
|
||||
// 音效 + 震屏(lua:只有自己击杀才播 PW_FlameStrike_Explosion/Die + 震屏/震手机)
|
||||
if (isSelfKill)
|
||||
{
|
||||
AudioManager.Instance.PlayerFXByName("PW_FlameStrike_Explosion");
|
||||
AudioManager.Instance.PlayerFXByName("PW_FlameStrike_Die");
|
||||
// ⭐ 震屏对齐 lua explosionShakeScreen(CameraShaker,参数与其它 Boss 死亡一致)
|
||||
if (GameManager.Instance != null && GameManager.Instance.cameraShake != null)
|
||||
GameManager.Instance.cameraShake.ShakePresets.Explosion2D(3f, 4f, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
AudioManager.Instance.PlayerFXByName("PW_FlameStrike_Explosion");
|
||||
}
|
||||
|
||||
bool isFreeBullet = ReadBulletType(param) == BulletTypeFree;
|
||||
StopFlow();
|
||||
_flowRoutine = StartCoroutine(DeadFlow(isFreeBullet, param));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ===== 未死亡:爆炸特效一下 + 播爆奖 → 关全部特效 → 恢复游动 =====
|
||||
// ⭐ 不再调 base.DieFish():原版未死亡时不震屏、不标 isDieFish(否则每次命中都会震屏)
|
||||
if (isSelfKill)
|
||||
AudioManager.Instance.PlayerFXByName("PW_FlameStrike_Explosion");
|
||||
|
||||
StopFlow();
|
||||
_flowRoutine = StartCoroutine(NotDeadFlow());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>未死亡流程(lua OnExplosion 的 else 分支):爆炸特效 → 0.3s 爆奖 → 0.8s 关特效 → 恢复游动</summary>
|
||||
private IEnumerator NotDeadFlow()
|
||||
{
|
||||
ShowEffect(EffectExplosion);
|
||||
|
||||
Debug.Log($"[LieYanFengBao] 未死亡:播放爆奖({explosionToRewardDelay}s 后)");
|
||||
|
||||
yield return new WaitForSeconds(explosionToRewardDelay);
|
||||
// 爆奖特效由 CreateFishManager 生成的 effect_DieAward(LieYanFengBaoEvent)负责
|
||||
|
||||
yield return new WaitForSeconds(rewardToResetDelay);
|
||||
|
||||
// 回到待机:关掉全部特效(lua ShowEffect(0))
|
||||
ShowEffect(0);
|
||||
|
||||
_flowRoutine = null;
|
||||
OnAwardFinished(); // 恢复游动(lua:Boss 继续走)
|
||||
}
|
||||
|
||||
/// <summary>死亡流程(lua OnExplosion 的 isDead 分支):爆炸特效 → 爆奖 → 1.8s 火球弹 → 回收</summary>
|
||||
private IEnumerator DeadFlow(bool isFreeBullet, JToken param)
|
||||
{
|
||||
ShowEffect(EffectExplosion);
|
||||
|
||||
yield return new WaitForSeconds(explosionToRewardDelay);
|
||||
// 爆奖特效(effect_DieAward + 事件)由 CreateFishManager 负责
|
||||
|
||||
if (isFreeBullet)
|
||||
{
|
||||
// lua:Free 子弹打死 → 0.8s 后直接销毁本体(不生成火球弹)
|
||||
yield return new WaitForSeconds(rewardToResetDelay);
|
||||
}
|
||||
else
|
||||
{
|
||||
// lua:Timer 1.8s → 生成火球弹 + 销毁本体
|
||||
yield return new WaitForSeconds(dieToFlameRoundDelay - explosionToRewardDelay > 0f
|
||||
? dieToFlameRoundDelay - explosionToRewardDelay
|
||||
: 0f);
|
||||
SpawnFlameRounds(param);
|
||||
}
|
||||
|
||||
_flowRoutine = null;
|
||||
RemoveBoss();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成火球弹(lua:从 Wheel 的第 i 个子节点朝外发射 BulletType.FlameRound)。
|
||||
/// sourceUIDList 来自 param.flameInfo;缺失时按 flameRoundFallbackCount 逐个 Wheel 子节点发射。
|
||||
/// </summary>
|
||||
private void SpawnFlameRounds(JToken param)
|
||||
{
|
||||
if (flameRoundBulletPrefab == null)
|
||||
{
|
||||
Debug.LogWarning("[LieYanFengBao] flameRoundBulletPrefab 未赋值,跳过火球弹生成");
|
||||
return;
|
||||
}
|
||||
if (_wheel == null)
|
||||
{
|
||||
Debug.LogWarning("[LieYanFengBao] Wheel 节点缺失,跳过火球弹生成");
|
||||
return;
|
||||
}
|
||||
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null)
|
||||
return;
|
||||
|
||||
// 发射数量:优先用服务端 sourceUIDList;缺失则回退配置数量
|
||||
var uidList = ReadSourceUIDList(param);
|
||||
int count = uidList != null && uidList.Count > 0 ? uidList.Count : Mathf.Max(0, flameRoundFallbackCount);
|
||||
count = Mathf.Min(count, _wheel.childCount);
|
||||
if (count <= 0)
|
||||
{
|
||||
Debug.LogWarning($"[LieYanFengBao] 火球弹数量为 0(Wheel 子节点={_wheel.childCount}),跳过");
|
||||
return;
|
||||
}
|
||||
|
||||
Transform bulletParent = CreateFishManager.Instance.bjEffectRoot != null
|
||||
? CreateFishManager.Instance.bjEffectRoot
|
||||
: null;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Transform point = _wheel.GetChild(i);
|
||||
if (point == null) continue;
|
||||
|
||||
Vector3 spawnPos = point.position;
|
||||
// ⭐ 方向 = Wheel 子节点相对本体的方向(lua:dir = point - self.pos,再取角度)
|
||||
Vector3 dir = spawnPos - transform.position;
|
||||
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
|
||||
|
||||
// BullitMove 的飞行方向是 transform.up → 角度要 -90° 才是 Z 旋转
|
||||
var bulletGo = BulletPool.Instance.Get(flameRoundBulletPrefab, spawnPos,
|
||||
Quaternion.Euler(0f, 0f, angle - 90f), bulletParent);
|
||||
if (bulletGo == null) continue;
|
||||
|
||||
bulletGo.name = $"FlameRound_{guid}_{i}";
|
||||
|
||||
var bullet = bulletGo.GetComponent<BullitMove>();
|
||||
if (bullet != null)
|
||||
{
|
||||
bullet.Init(); // ⭐ 池化复用必须重新对齐起点
|
||||
bullet.moveSpeed = flameRoundSpeed;
|
||||
bullet.desTime = flameRoundLifeTime;
|
||||
bullet.userid = null;
|
||||
bullet.playerID = null;
|
||||
bullet.bulletID = bulletGo.name;
|
||||
Debug.Log($"[LieYanFengBao] 火球弹[{i}] 发射 从{spawnPos} 角度={angle:0.0}(sourceUID={(uidList != null && i < uidList.Count ? uidList[i].ToString() : "-")})");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[LieYanFengBao] 火球弹预制体上没有 BullitMove,无法控制飞行");
|
||||
}
|
||||
}
|
||||
// 未死亡:不删除,等爆奖结束 OnAwardFinished 恢复游动
|
||||
}
|
||||
|
||||
/// <summary>初始化爆奖事件(炸一下 + bjEndUI)</summary>
|
||||
private void InitAwardEffect(GameObject o, RoomKillNotice obj, int beishu)
|
||||
{
|
||||
Vector3 diePos = _diePosCached ? _diePos : transform.position;
|
||||
|
||||
if (obj == null) return;
|
||||
|
||||
Vector3 diePos = _diePosCached ? _diePos : transform.position;
|
||||
|
||||
foreach (var item in CreateFishManager.Instance.currGameType.list_Sits)
|
||||
{
|
||||
if (item.user == obj.userId)
|
||||
@@ -117,6 +381,10 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
evt.bossCtrl = this;
|
||||
currEvent = evt;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[LieYanFengBao] 爆奖预制体上没有 LieYanFengBaoEvent!只走基类流程");
|
||||
}
|
||||
|
||||
v.Init(
|
||||
obj.gold,
|
||||
@@ -132,30 +400,6 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下一帧删除 Boss:Ws_DieFish 在 DieFish 返回后同帧会实例化爆奖特效并触发回调。
|
||||
/// 等到下一帧:Boss 被删除;爆奖事件没初始化(座位没找到)则把特效实例回池。
|
||||
/// </summary>
|
||||
private System.Collections.IEnumerator RemoveBossNextFrame()
|
||||
{
|
||||
yield return null;
|
||||
|
||||
if (!_removed)
|
||||
{
|
||||
_removed = true;
|
||||
|
||||
if (!_awardInitCalled && currEffect_DieAward != null)
|
||||
{
|
||||
var effect = currEffect_DieAward;
|
||||
currEffect_DieAward = null;
|
||||
EffectPool.Instance.Return(effect);
|
||||
}
|
||||
|
||||
CreateFishManager.Instance.Id_DieFish_NotFX(guid);
|
||||
Debug.Log($"[LieYanFengBao] Boss 已删除 guid={guid}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>爆奖流程结束回调(Event 调用):未死亡时恢复游动</summary>
|
||||
public void OnAwardFinished()
|
||||
{
|
||||
@@ -163,16 +407,126 @@ public class LieYanFengBao_BOSS : MonsterControl_BossBase
|
||||
{
|
||||
ChangeState(CharacterStateType.move);
|
||||
isMove = true;
|
||||
// ⭐ 复位死亡标记(同 XingJiXunHang):非最终死亡 Boss 不回池,
|
||||
// isDead 卡 true 会让锁定子弹被 BullitMove 判 target.isDead 立即 NotLock
|
||||
// ⭐ 复位死亡标记:非最终死亡 Boss 不回池,isDead 卡 true 会让锁定子弹立即 NotLock
|
||||
isDead = false;
|
||||
Debug.Log("[LieYanFengBao] 未死亡爆奖结束,恢复游动");
|
||||
}
|
||||
currEvent = null;
|
||||
}
|
||||
|
||||
/// <summary>回收本体(等火球弹生成后再删,保证发射点位置正确)</summary>
|
||||
private void RemoveBoss()
|
||||
{
|
||||
if (_removed) return;
|
||||
_removed = true;
|
||||
|
||||
// 兜底:爆奖事件没初始化(击杀者不在座位列表)→ 把爆奖特效实例回池
|
||||
if (!_awardInitCalled && currEffect_DieAward != null)
|
||||
{
|
||||
var effect = currEffect_DieAward;
|
||||
currEffect_DieAward = null;
|
||||
EffectPool.Instance.Return(effect);
|
||||
}
|
||||
|
||||
if (CreateFishManager.Instance != null)
|
||||
CreateFishManager.Instance.Id_DieFish_NotFX(guid);
|
||||
Debug.Log($"[LieYanFengBao] Boss 已回收 guid={guid}");
|
||||
}
|
||||
|
||||
private void StopFlow()
|
||||
{
|
||||
if (_flowRoutine != null)
|
||||
{
|
||||
StopCoroutine(_flowRoutine);
|
||||
_flowRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// param 辅助解析(原版数据在 data.flameInfo / data.bulletType 上)
|
||||
// ================================================================
|
||||
|
||||
/// <summary>读 param.bulletType(原版 data.bulletType,1=Free)</summary>
|
||||
private static int ReadBulletType(JToken param)
|
||||
{
|
||||
if (param is JObject o && o["bulletType"] != null)
|
||||
{
|
||||
try { return o["bulletType"].Value<int>(); } catch { }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>读 param.flameInfo.sourceUIDList(火球弹来源列表)</summary>
|
||||
private static List<JToken> ReadSourceUIDList(JToken param)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (param is JObject o)
|
||||
{
|
||||
var info = o["flameInfo"] as JObject;
|
||||
if (info != null && info["sourceUIDList"] is JArray arr)
|
||||
return new List<JToken>(arr);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[LieYanFengBao] 解析 flameInfo 失败: {e.Message}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 查找工具
|
||||
// ================================================================
|
||||
|
||||
/// <summary>按 "Body/Bone" 这类路径逐级查找(忽略大小写)</summary>
|
||||
private Transform FindByPath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return null;
|
||||
Transform cur = transform;
|
||||
foreach (var part in path.Split('/'))
|
||||
{
|
||||
Transform next = null;
|
||||
for (int i = 0; i < cur.childCount; i++)
|
||||
{
|
||||
if (string.Equals(cur.GetChild(i).name, part, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
next = cur.GetChild(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (next == null) return null;
|
||||
cur = next;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
/// <summary>在 Bone 下找特效节点,找不到再全树递归兜底</summary>
|
||||
private GameObject FindEffectNode(Transform bone, string name)
|
||||
{
|
||||
Transform t = bone != null ? bone.Find(name) : null;
|
||||
if (t == null) t = FindChildRecursive(transform, name);
|
||||
if (t == null) Debug.LogWarning($"[LieYanFengBao] 找不到特效节点 {name}");
|
||||
return t != null ? t.gameObject : null;
|
||||
}
|
||||
|
||||
/// <summary>递归查找子物体(忽略大小写)</summary>
|
||||
private static Transform FindChildRecursive(Transform root, string name)
|
||||
{
|
||||
if (root == null) return null;
|
||||
for (int i = 0; i < root.childCount; i++)
|
||||
{
|
||||
Transform c = root.GetChild(i);
|
||||
if (string.Equals(c.name, name, StringComparison.OrdinalIgnoreCase)) return c;
|
||||
Transform r = FindChildRecursive(c, name);
|
||||
if (r != null) return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
_flowRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user