588 lines
23 KiB
C#
588 lines
23 KiB
C#
using Assets.MyGame.Scripts.Net.WebResponses;
|
||
using DG.Tweening;
|
||
using Newtonsoft.Json.Linq;
|
||
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 幸运轮 Boss 爆奖事件(Boss 控制流程模式,参照破坏球 PoHuaiQiuEvent)。
|
||
///
|
||
/// 新流程(按用户要求的顺序创建规则):
|
||
/// 1. Init: 解析服务端参数,填充 _targetSlots,不预创建 item
|
||
/// 2. FlyToSeat: 计算 3D item 目标位置,启动顺序协程
|
||
/// 3. 顺序协程 SequentialItemFlow:
|
||
/// - 创建第1个 item → 移动到目标位置(flyDuration) → 旋转(rotateDuration)
|
||
/// - 创建第2个 item → 直接设位置(无移动效果) → 旋转
|
||
/// - 创建第3个 item → 直接设位置 → 旋转
|
||
/// - ... 依次类推
|
||
/// - 最后一个 item 转完后等2秒 → EndExplosion()
|
||
///
|
||
/// 服务端 param 格式:{ "res": [{optionId, triggerRate, score}], "count": N }
|
||
/// optionId = 分值(如 130/300/280),映射到 slotScores 中匹配的格子索引
|
||
/// </summary>
|
||
public class XingYunLunEvent : BJRedPacketEvent
|
||
{
|
||
public GameObject BJFXEffectModel; // 爆奖特效模型(转轮预制体)
|
||
|
||
[Header("爆奖 item")]
|
||
[Tooltip("item 之间的 x 轴间隔(世界坐标单位)")]
|
||
public float itemGapX = 2f;
|
||
|
||
[Header("爆奖特效模型旋转")]
|
||
[Tooltip("额外旋转圈数(让转盘有转动效果)")]
|
||
public int extraSpins = 2;
|
||
[Tooltip("旋转动画时长(秒)")]
|
||
public float rotateDuration = 1.5f;
|
||
[Tooltip("每个格子的爆奖倍数(按格子顺序,共8个)")]
|
||
public int[] slotScores = { 50, 100, 230, 80, 280, 300, 130, 250 };
|
||
[Tooltip("每个格子的固定角度(按格子顺序,共8个)")]
|
||
public float[] slotAngles = { 0f, 45f, 90f, 135f, 180f, 225f, 270f, 315f };
|
||
|
||
/// <summary>转动位置(世界坐标,由 Boss 传入=死亡位置)</summary>
|
||
[HideInInspector]
|
||
public Vector3 explosionCenter = Vector3.zero;
|
||
|
||
/// <summary>已创建的 item(对象池复用需清理)</summary>
|
||
private List<GameObject> _items = new List<GameObject>();
|
||
|
||
/// <summary>服务端下发的选项列表(用于映射格子)</summary>
|
||
private List<BossKillOption> _cardParams = new List<BossKillOption>();
|
||
|
||
/// <summary>每个 item 的目标格子索引</summary>
|
||
private List<int> _targetSlots = new List<int>();
|
||
|
||
[Header("飞向座位上方")]
|
||
[Tooltip("座位上方偏移(Canvas 单位)")]
|
||
public float seatUpOffset = 150f;
|
||
[Tooltip("3D item 在世界坐标中向上偏移,微调位置用")]
|
||
public float worldUpOffset = 1f;
|
||
[Tooltip("分数面板相对最后一个item的偏移(Canvas坐标,x=水平偏移 y=垂直偏移)")]
|
||
public Vector2 scorePanelOffset = new Vector2(0f, 200f);
|
||
[Tooltip("第一个 item 飞到座位上方时长(秒)")]
|
||
public float flyDuration = 0.8f;
|
||
|
||
|
||
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu,
|
||
Action<int> action, Action action1 = null)
|
||
{
|
||
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
|
||
|
||
// 定位到 Boss 传入的转动位置
|
||
transform.position = explosionCenter;
|
||
|
||
// Step1: 解析服务端参数
|
||
ParseCardParams();
|
||
|
||
// Step2: 根据 _cardParams 填充 _targetSlots(不再预创建 item)
|
||
FillTargetSlots();
|
||
|
||
// 直接显示最终分数(不滚动,Boss 控制时序)
|
||
if (tMP_Score != null)
|
||
tMP_Score.text = maxScore.ToString();
|
||
}
|
||
|
||
/// <summary>重写:不移动到屏幕中心,只缓存座位引用(供 isSelf 判断使用)</summary>
|
||
protected override void ApplySeatOffset()
|
||
{
|
||
GetSeatPosition();
|
||
}
|
||
|
||
// ============================================================
|
||
#region 解析服务端参数
|
||
// ============================================================
|
||
|
||
private void ParseCardParams()
|
||
{
|
||
_cardParams.Clear();
|
||
|
||
if (obj == null)
|
||
{
|
||
Debug.LogWarning("[XingYunLun] param 为 null");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
JToken rootToken = obj is JToken t ? t : JToken.Parse(obj.ToString());
|
||
JToken resToken = rootToken["res"] ?? rootToken;
|
||
|
||
if (resToken is JArray jarr)
|
||
_cardParams = jarr.ToObject<List<BossKillOption>>() ?? new List<BossKillOption>();
|
||
else if (resToken is JObject jobj)
|
||
_cardParams = new List<BossKillOption> { jobj.ToObject<BossKillOption>() };
|
||
else
|
||
_cardParams = new List<BossKillOption>();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError($"[XingYunLun] 解析参数失败:{e.Message};原始={obj}");
|
||
_cardParams = new List<BossKillOption>();
|
||
}
|
||
|
||
Debug.Log($"[XingYunLun] 解析到 {_cardParams.Count} 个选项: " +
|
||
$"[{string.Join(", ", _cardParams.Select(p => p.score))}]");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据 _cardParams 填充 _targetSlots。
|
||
/// </summary>
|
||
private void FillTargetSlots()
|
||
{
|
||
_targetSlots.Clear();
|
||
|
||
int count = _cardParams.Count;
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
if (_cardParams[i] != null)
|
||
{
|
||
int score = (int)_cardParams[i].score;
|
||
int slotIdx = FindSlotByScore(score);
|
||
_targetSlots.Add(slotIdx);
|
||
Debug.Log($"[XingYunLun] item[{i}] score={score} → slot={slotIdx}");
|
||
}
|
||
else
|
||
{
|
||
int lastSlot = _targetSlots.Count > 0 ? _targetSlots[_targetSlots.Count - 1] : 0;
|
||
_targetSlots.Add(lastSlot);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>根据 score 在 slotScores 中查找索引,找不到则返回 0</summary>
|
||
private int FindSlotByScore(int score)
|
||
{
|
||
for (int i = 0; i < slotScores.Length; i++)
|
||
{
|
||
if (slotScores[i] == score) return i;
|
||
}
|
||
Debug.LogWarning($"[XingYunLun] score={score} 在 slotScores 中未找到,默认0");
|
||
return 0;
|
||
}
|
||
|
||
#endregion
|
||
|
||
// ============================================================
|
||
#region item 创建与清理
|
||
// ============================================================
|
||
|
||
private void ClearAllItems()
|
||
{
|
||
if (_items == null) return;
|
||
foreach (var c in _items)
|
||
{
|
||
if (c != null) Destroy(c);
|
||
}
|
||
_items.Clear();
|
||
}
|
||
|
||
#endregion
|
||
|
||
// ============================================================
|
||
#region 飞向座位与顺序旋转
|
||
// ============================================================
|
||
|
||
/// <summary>
|
||
/// 爆奖效果飞到玩家座位上方,然后依次创建并旋转每个转轮。
|
||
/// </summary>
|
||
public void FlyToSeat()
|
||
{
|
||
float yOffset = seatUpOffset;
|
||
if (posID == 2 || posID == 3) yOffset *= -1f;
|
||
Vector3 seatWorld = GetSeatPosition() + Vector3.up * yOffset;
|
||
|
||
var canvasGo = UIManager.Instance.uiRoot;
|
||
var canvasComp = canvasGo.GetComponent<Canvas>();
|
||
|
||
// Step 1: Event(UI) 直接移动到目标 Canvas 坐标
|
||
Vector2 canvasTarget = CoordinateTransformation.WorldPos_ToCanvas(seatWorld, canvasComp);
|
||
var rt = GetComponent<RectTransform>();
|
||
if (rt != null)
|
||
{
|
||
rt.DOAnchorPos(canvasTarget, flyDuration);
|
||
}
|
||
else
|
||
{
|
||
transform.DOMove(seatWorld, flyDuration);
|
||
}
|
||
|
||
// Step 2: 计算 3D item 基础目标位置(轮子中心对准座位点)
|
||
RectTransform canvasRT = canvasGo.GetComponent<RectTransform>();
|
||
RectTransform seatRT = GetSeatRectTransform();
|
||
|
||
Vector3 modelBaseTarget;
|
||
if (seatRT != null)
|
||
{
|
||
Vector3 r1 = CoordinateTransformation.UIToWorld(seatRT, canvasRT);
|
||
|
||
Camera cam = canvasComp.renderMode == RenderMode.ScreenSpaceOverlay ? Camera.main : canvasComp.worldCamera;
|
||
float worldHeight = cam.orthographicSize * 2f;
|
||
float worldYOffset = yOffset * worldHeight / canvasRT.rect.height;
|
||
r1.y += worldYOffset + worldUpOffset;
|
||
r1.z = -100f;
|
||
|
||
int totalCount = _targetSlots.Count;
|
||
Debug.Log($"[XingYunLun][坐标转换] UIToWorld={r1} totalCount={totalCount} centerOffset={(totalCount - 1) / 2f * itemGapX}");
|
||
modelBaseTarget = r1 - new Vector3((totalCount - 1) / 2f * itemGapX, 0f, 0f);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("[XingYunLun][坐标转换] seatRT 为 null,降级 CalcModelTargetWorldPos");
|
||
modelBaseTarget = CalcModelTargetWorldPos(seatWorld, canvasComp);
|
||
}
|
||
|
||
// Step 3: 启动顺序创建+旋转协程
|
||
StartCoroutine(SequentialItemFlow(modelBaseTarget));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 顺序流程:创建第1个 item → 移动 → 旋转 → 创建第2个 → 旋转 → ... → 最后等2秒 → EndExplosion
|
||
/// </summary>
|
||
private IEnumerator SequentialItemFlow(Vector3 modelBaseTarget)
|
||
{
|
||
ClearAllItems();
|
||
|
||
int totalItems = _targetSlots.Count;
|
||
if (totalItems <= 0)
|
||
{
|
||
Debug.LogWarning("[XingYunLun] _targetSlots 为空,直接结束");
|
||
yield return new WaitForSeconds(2f);
|
||
EndExplosion();
|
||
yield break;
|
||
}
|
||
|
||
// 音效:幸运大转盘出场(PW_FortuneWheel_Show,转轮开始出现)
|
||
AudioManager.Instance.PlayerFXByName("PW_FortuneWheel_Show");
|
||
|
||
// 计算所有 item 的倍数总和(给中间转轮的 BJEndLabel 用)
|
||
int totalScoreSum = 0;
|
||
for (int s = 0; s < _targetSlots.Count; s++)
|
||
{
|
||
int si = _targetSlots[s];
|
||
totalScoreSum += (si < slotScores.Length) ? slotScores[si] : 0;
|
||
}
|
||
|
||
// 存储每个 item 的原始位置,供 shift 后恢复
|
||
var originalPositions = new Dictionary<GameObject, Vector3>();
|
||
float shiftAmount = itemGapX * 0.3f;
|
||
|
||
for (int i = 0; i < totalItems; i++)
|
||
{
|
||
// 创建 item
|
||
// ⭐ 轮子克隆挂 bjEffectRoot(世界空间爆奖特效统一父节点,ExitRoom 退房会清空其子物体):
|
||
// 之前不挂父对象落到场景根——爆奖没播完就退房时事件被销毁、协程中断走不到 ClearAllItems,
|
||
// 场景根下的轮子没人清 → 永远卡在屏幕上。bjEffectRoot 为原点恒等变换,不影响世界坐标摆放
|
||
Transform lunParent = CreateFishManager.Instance != null ? CreateFishManager.Instance.bjEffectRoot : null;
|
||
var clone = Instantiate(BJFXEffectModel, lunParent);
|
||
clone.transform.rotation = Quaternion.identity;
|
||
clone.name = BJFXEffectModel.name + "_item_" + i;
|
||
clone.SetActive(true);
|
||
_items.Add(clone);
|
||
|
||
LunItem lunItem = clone.GetComponent<LunItem>();
|
||
|
||
// 初始关闭所有特效
|
||
if (lunItem != null)
|
||
{
|
||
if (lunItem.obj_XuanZhuanEffect != null) lunItem.obj_XuanZhuanEffect.SetActive(false);
|
||
if (lunItem.objs_IEffect != null)
|
||
foreach (var e in lunItem.objs_IEffect) if (e != null) e.SetActive(false);
|
||
if (lunItem.objs_REffect != null)
|
||
foreach (var e in lunItem.objs_REffect) if (e != null) e.SetActive(false);
|
||
}
|
||
|
||
Vector3 targetPos = modelBaseTarget + new Vector3(itemGapX * i, 0f, 0f);
|
||
originalPositions[clone] = targetPos;
|
||
|
||
// 第一个 item:移动到目标位置(有移动效果)
|
||
if (i == 0)
|
||
{
|
||
bool moveDone = false;
|
||
clone.transform.DOKill();
|
||
clone.transform.DOMove(targetPos, flyDuration)
|
||
.OnComplete(() => moveDone = true);
|
||
yield return new WaitUntil(() => moveDone);
|
||
}
|
||
else
|
||
{
|
||
// 后续 item:直接设位置(无移动效果)
|
||
clone.transform.position = targetPos;
|
||
}
|
||
|
||
// === 当前轮子放大到当前大小的1.5倍,其他轮子往旁边移动 ===
|
||
Vector3 originalScale = clone.transform.localScale;
|
||
Vector3 targetScale = originalScale * 1.5f;
|
||
bool scaleUpDone = false;
|
||
clone.transform.DOScale(targetScale, 0.2f).SetEase(Ease.OutBack)
|
||
.OnComplete(() => scaleUpDone = true);
|
||
yield return new WaitUntil(() => scaleUpDone);
|
||
|
||
// 其他已存在的轮子往旁边移动
|
||
for (int j = 0; j < _items.Count; j++)
|
||
{
|
||
if (_items[j] == clone) continue;
|
||
int dir = (j < i) ? -1 : 1;
|
||
Vector3 shifted = originalPositions[_items[j]] + new Vector3(dir * shiftAmount, 0f, 0f);
|
||
_items[j].transform.DOMove(shifted, 0.2f).SetEase(Ease.OutCubic);
|
||
}
|
||
yield return new WaitForSeconds(0.2f);
|
||
|
||
// 激活旋转特效
|
||
if (lunItem != null && lunItem.obj_XuanZhuanEffect != null)
|
||
lunItem.obj_XuanZhuanEffect.SetActive(true);
|
||
|
||
// 音效:幸运大转盘开始转动(PW_FortuneWheel_TurnBegin)
|
||
AudioManager.Instance.PlayerFXByName("PW_FortuneWheel_TurnBegin");
|
||
|
||
// 旋转(用固定角度数组,不用公式计算)
|
||
int slotIdx = (i < _targetSlots.Count) ? _targetSlots[i] : 0;
|
||
float slotAngle = (slotIdx < slotAngles.Length) ? slotAngles[slotIdx] : 0f;
|
||
float totalAngle = extraSpins * 360f + slotAngle;
|
||
int beishu = (slotIdx < slotScores.Length) ? slotScores[slotIdx] : 0;
|
||
|
||
Debug.Log($"[XingYunLun] item[{i}] → 格子{slotIdx} ({slotAngle}°) 倍数={beishu} 旋转总角度={totalAngle}°");
|
||
|
||
bool rotateDone = false;
|
||
clone.transform.DOKill();
|
||
clone.transform.DORotate(
|
||
new Vector3(totalAngle, 0f, 0f),
|
||
rotateDuration,
|
||
RotateMode.WorldAxisAdd
|
||
).SetEase(Ease.OutCubic)
|
||
.OnComplete(() =>
|
||
{
|
||
rotateDone = true;
|
||
// 音效:幸运大转盘确认(PW_FortuneWheel_Confirm,停到格子)
|
||
AudioManager.Instance.PlayerFXByName("PW_FortuneWheel_Confirm");
|
||
// 旋转完成:关闭旋转特效,激活对应格子的 IEffect 和 REffect
|
||
if (lunItem != null)
|
||
{
|
||
if (lunItem.obj_XuanZhuanEffect != null) lunItem.obj_XuanZhuanEffect.SetActive(false);
|
||
if (lunItem.objs_IEffect != null && slotIdx < lunItem.objs_IEffect.Count && lunItem.objs_IEffect[slotIdx] != null)
|
||
lunItem.objs_IEffect[slotIdx].SetActive(true);
|
||
if (lunItem.objs_REffect != null && slotIdx < lunItem.objs_REffect.Count && lunItem.objs_REffect[slotIdx] != null)
|
||
lunItem.objs_REffect[slotIdx].SetActive(true);
|
||
}
|
||
});
|
||
|
||
yield return new WaitUntil(() => rotateDone);
|
||
|
||
// === 旋转完成后:恢复当前轮子大小,恢复其他轮子位置 ===
|
||
clone.transform.DOScale(originalScale, 0.3f).SetEase(Ease.OutCubic);
|
||
for (int j = 0; j < _items.Count; j++)
|
||
{
|
||
if (_items[j] == clone) continue;
|
||
if (originalPositions.ContainsKey(_items[j]))
|
||
_items[j].transform.DOMove(originalPositions[_items[j]], 0.3f).SetEase(Ease.OutCubic);
|
||
}
|
||
yield return new WaitForSeconds(0.3f);
|
||
}
|
||
|
||
// 全部转轮转完后:显示总分面板
|
||
CreateScorePanel(totalScoreSum);
|
||
|
||
// 分数面板显示1秒后销毁
|
||
if (_scoreBoard != null)
|
||
{
|
||
StartCoroutine(DelayDestroyScorePanel(1f));
|
||
}
|
||
|
||
// 所有 item 转完后等2秒结束爆奖
|
||
Debug.Log("[XingYunLun] 所有转轮旋转完成,等待2秒后结束");
|
||
yield return new WaitForSeconds(2f);
|
||
EndExplosion();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取座位上的 RectTransform(供 UIToWorld 使用)。
|
||
/// </summary>
|
||
private RectTransform GetSeatRectTransform()
|
||
{
|
||
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null)
|
||
return null;
|
||
var sits = CreateFishManager.Instance.currGameType.list_Sits;
|
||
if (posID < 0 || posID >= sits.Count || sits[posID] == null)
|
||
return null;
|
||
|
||
SitPosData sit = sits[posID];
|
||
|
||
if (sit.obj_BaoJiangZhongPanelPosition != null)
|
||
{
|
||
var rt = sit.obj_BaoJiangZhongPanelPosition.GetComponent<RectTransform>();
|
||
if (rt != null) return rt;
|
||
}
|
||
if (sit.currentTurret != null)
|
||
{
|
||
var rt = sit.currentTurret.GetComponent<RectTransform>();
|
||
if (rt != null) return rt;
|
||
}
|
||
return sit.GetComponent<RectTransform>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算 3D 模型目标世界坐标(降级用)。
|
||
/// </summary>
|
||
private Vector3 CalcModelTargetWorldPos(Vector3 seatWorld, Canvas canvas)
|
||
{
|
||
RectTransform canvasRT = canvas.GetComponent<RectTransform>();
|
||
Camera cam = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? Camera.main : canvas.worldCamera;
|
||
|
||
Vector2 canvasPos = CoordinateTransformation.WorldPos_ToCanvas(seatWorld, canvas);
|
||
Vector3 worldTarget = CoordinateTransformation.CanvasToWorld(canvasPos, canvasRT, cam);
|
||
worldTarget.z = -100f;
|
||
return worldTarget;
|
||
}
|
||
|
||
#endregion
|
||
|
||
// ============================================================
|
||
#region 分数面板
|
||
// ============================================================
|
||
|
||
/// <summary>
|
||
/// 创建分数面板:用 scorePanelPrefab 显示总分,定位在幸运轮上方。
|
||
/// </summary>
|
||
private void CreateScorePanel(int totalScore)
|
||
{
|
||
if (scorePanelPrefab == null)
|
||
{
|
||
Debug.LogWarning("[XingYunLun] scorePanelPrefab 为 null,跳过分数面板创建");
|
||
return;
|
||
}
|
||
|
||
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null) return;
|
||
|
||
// ⭐ 与其他 Boss(小丑扑克/黑洞/普通鱼爆奖)保持一致:
|
||
// 分数面板挂在 subPanelParent.parent 下,坐标以 uiRoot Canvas 为基准,
|
||
// 否则 subPanelParent 与 Canvas 坐标系不一致会导致 scorePanelOffset 偏移不生效。
|
||
var parent = CreateFishManager.Instance.currGameType.subPanelParent?.parent;
|
||
if (parent == null) return;
|
||
|
||
var board = Instantiate(scorePanelPrefab, parent);
|
||
_scoreBoard = board;
|
||
|
||
_bjImage = board.GetComponentInChildren<BJImage>();
|
||
if (_bjImage != null && _bjImage.tmp_CoinNum != null)
|
||
{
|
||
tMP_Score = _bjImage.tmp_CoinNum;
|
||
}
|
||
else
|
||
{
|
||
var tmp = board.GetComponentInChildren<TextMeshProUGUI>();
|
||
if (tmp != null) tMP_Score = tmp;
|
||
}
|
||
|
||
if (tMP_Score != null)
|
||
tMP_Score.text = totalScore.ToString();
|
||
|
||
// 面板定位:最后一个 item 的位置 + offset(Canvas坐标偏移)
|
||
Vector3 lastItemPos = _items.Count > 0 ? _items[_items.Count - 1].transform.position : transform.position;
|
||
Vector3 worldTarget = lastItemPos + Vector3.up * worldUpOffset;
|
||
|
||
// ⭐ 与 GetUiCanvas() 同源:以 UIManager.uiRoot 的 Canvas 为转换基准
|
||
Canvas canvas = UIManager.Instance != null && UIManager.Instance.uiRoot != null
|
||
? UIManager.Instance.uiRoot.GetComponent<Canvas>()
|
||
: parent.GetComponentInParent<Canvas>();
|
||
if (canvas == null) return;
|
||
Vector2 canvasPos = CoordinateTransformation.WorldPos_ToCanvas(worldTarget, canvas);
|
||
Vector2 canvasPosBeforeOffset = canvasPos; // 记录加偏移前的坐标
|
||
canvasPos += scorePanelOffset;
|
||
RectTransform rt = board.GetComponent<RectTransform>();
|
||
rt.anchoredPosition = canvasPos;
|
||
|
||
Debug.Log($"[XingYunLun] 分数面板创建 总分={totalScore} worldPos={worldTarget} " +
|
||
$"加偏移前={canvasPosBeforeOffset} scorePanelOffset={scorePanelOffset} 加偏移后={canvasPos} " +
|
||
$"父节点={board.transform.parent.name}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延迟销毁分数面板
|
||
/// </summary>
|
||
private IEnumerator DelayDestroyScorePanel(float delay)
|
||
{
|
||
yield return new WaitForSeconds(delay);
|
||
if (_scoreBoard != null)
|
||
{
|
||
Destroy(_scoreBoard);
|
||
_scoreBoard = null;
|
||
tMP_Score = null;
|
||
_bjImage = null;
|
||
Debug.Log("[XingYunLun] 分数面板已销毁");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
// ============================================================
|
||
#region 爆奖结束与回池
|
||
// ============================================================
|
||
|
||
/// <summary>
|
||
/// Boss 流程结束后调用:创建 bjEndUI 并结束爆奖。
|
||
/// </summary>
|
||
public void EndExplosion()
|
||
{
|
||
if (isScoreEnd) return;
|
||
isScoreEnd = true;
|
||
|
||
// 音效:幸运大转盘结算(PW_FortuneWheel_Settle)
|
||
AudioManager.Instance.PlayerFXByName("PW_FortuneWheel_Settle");
|
||
|
||
// 回加金币到玩家
|
||
JiaFen?.Invoke();
|
||
|
||
// bjEndUI 定位在炮台上方
|
||
if (bjEndUI != null)
|
||
{
|
||
float y = bjEndUIOffsetY;
|
||
if (posID == 2 || posID == 3) y *= -1f;
|
||
Vector3 uiPos = GetSeatPosition() + Vector3.up * y;
|
||
|
||
var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, GetBJEndUIParent());
|
||
endUI.Init(bJbeishu, maxScore, isSelf);
|
||
}
|
||
|
||
// 回收所有 item
|
||
ClearAllItems();
|
||
|
||
// 分数面板由 DelayDestroyScorePanel 协程在1秒后自动销毁,
|
||
// 如果协程因 StopAllCoroutines 被中断,这里兜底清理
|
||
CleanupScoreBoard();
|
||
|
||
die();
|
||
}
|
||
|
||
/// <summary>回收爆奖预制体到对象池</summary>
|
||
public override void die()
|
||
{
|
||
CleanupBeforeDie();
|
||
EffectPool.Instance.Return(gameObject);
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
StopAllCoroutines();
|
||
// ⭐ 兜底清理轮子:协程被中断(退房销毁事件)时走不到 ClearAllItems,
|
||
// 虽然轮子已挂 bjEffectRoot 会被 ExitRoom 清空,这里再兜一层防残留
|
||
ClearAllItems();
|
||
CleanupScoreBoard();
|
||
}
|
||
|
||
/// <summary>清理分数面板(兜底)</summary>
|
||
private void CleanupScoreBoard()
|
||
{
|
||
if (_scoreBoard != null)
|
||
{
|
||
Destroy(_scoreBoard);
|
||
_scoreBoard = null;
|
||
tMP_Score = null;
|
||
_bjImage = null;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|