594 lines
23 KiB
C#
594 lines
23 KiB
C#
using Assets.MyGame.Scripts.Net.WebResponses;
|
||
using DG.Tweening;
|
||
using Newtonsoft.Json.Linq;
|
||
using System;
|
||
using System.Collections;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
/// <summary>
|
||
/// 风雷之渊·神龙转盘 Boss 爆奖事件(三层转盘,参照 RotatePan_XJMH)。
|
||
///
|
||
/// 升级型三层转盘(停靠路径全部由客户端自算,不依赖服务端 option)。
|
||
///
|
||
/// 最终倍数:服务端 res.beizhu 优先,否则取顶层 RoomKillNotice.beishu(Init 传入)。
|
||
///
|
||
/// 升级规则:数值表里的 -1 是“升级格”——
|
||
/// 外圈停在 -1 → 升级转中圈;中圈停在 -1 → 升级转内圈;内圈直接出最终倍数。
|
||
///
|
||
/// 路径自算(从内圈往外圈判断):
|
||
/// 1. 内圈表里有该倍数(如 10000/20000)→ 外圈、中圈都停 -1,内圈停该倍数;
|
||
/// 2. 中圈、外圈表里都有(如 300/500/600)→ 一半概率外圈直接停,一半概率外圈-1升级到中圈停;
|
||
/// 3. 仅中圈有(如 800/1000)→ 外圈停 -1,中圈停该倍数;
|
||
/// 4. 仅外圈有(如 350/550/650/700)→ 外圈直接停该倍数。
|
||
/// 不参与升级链的圈持续慢转(停靠值=0),停 -1 的圈精确停在升级格。
|
||
///
|
||
/// 显示:txt_BeiShu / tMP_BeiShu 直接输出最终倍数数字,无任何加减计算。
|
||
///
|
||
/// 流程:
|
||
/// Boss 死亡 → Init(定位到击杀者座位上方偏移处 + 读最终倍数)→ 三层转盘按 外→中→内 依次旋转
|
||
/// → 参与的圈精确停在对应格子正点(含 -1 升级格,无任何随机偏移)
|
||
/// → 不参与的圈持续慢转 → 全部停稳后显示最终倍数
|
||
/// → StartAddScore(RollNumber 快速滚动总分,基类逐帧加底分模式滚不完巨量分数)
|
||
/// → MoveToSit → OnScoreEnd → JiaFen → die
|
||
///
|
||
/// ⚠️ waiValues / zhongValues / neiValues 三张数值表必须与转盘美术各圈格子数值
|
||
/// 完全一致(-1 为升级格),否则停靠格子会找错。
|
||
/// </summary>
|
||
public class SLZPDieEvent : BJRedPacketEvent
|
||
{
|
||
[Header("转盘")]
|
||
public Transform wai; // 外圈转盘
|
||
public Transform zhong; // 中圈转盘
|
||
public Transform nei; // 内圈转盘
|
||
|
||
[Header("旋转参数")]
|
||
public int spinRounds = 5; // 旋转圈数(到达目标前转的圈数)
|
||
public float rotateDuration = 2f; // 单圈旋转总时长
|
||
public float waiDir = -1f; // 外圈方向(-1逆时针,1顺时针)
|
||
public float zhongDir = 1f; // 中圈方向(-1逆时针,1顺时针)
|
||
public float neiDir = -1f; // 内圈方向(-1逆时针,1顺时针)
|
||
[Tooltip("不参与升级链的圈(停靠值=0)持续慢转一圈的秒数")]
|
||
public float idleSpinDuration = 3f; // 不参与升级链的圈的慢转速度
|
||
|
||
[Header("三圈数值表(-1=升级格,必须与转盘美术格子数值一致)")]
|
||
[Tooltip("外圈数值(wai):抽到-1升级到中圈")]
|
||
private int[] waiValues = new int[] { -1, 50, 100, 200, 300, 400, 500, 600 };
|
||
[Tooltip("中圈数值(zhong):抽到-1升级到内圈")]
|
||
private int[] zhongValues = new int[] { -1, 100, 200, 300, 400, 500 };
|
||
[Tooltip("内圈数值(nei):直接出最终倍数")]
|
||
private int[] neiValues = new int[] { -1, 10000, 20000 };
|
||
|
||
[Header("抽中高亮(转盘背后,索引与各数值表一一对应,停哪格亮哪格)")]
|
||
[Tooltip("外圈各格抽中效果,索引与 waiValues 一一对应")]
|
||
public GameObject[] waiFx;
|
||
[Tooltip("中圈各格抽中效果,索引与 zhongValues 一一对应")]
|
||
public GameObject[] zhongFx;
|
||
[Tooltip("内圈各格抽中效果,索引与 neiValues 一一对应")]
|
||
public GameObject[] neiFx;
|
||
|
||
[Header("座位定位")]
|
||
[Tooltip("转盘在座位上方的偏移(UI 大件需要足够偏移避开炮台);2/3号座位在下方,自动翻转向下")]
|
||
public float seatOffsetY = 400f;
|
||
|
||
[Header("转完后加分延迟")]
|
||
public float scoreStartDelay = 0.5f; // 转盘停稳后到加分的延迟
|
||
[Tooltip("升级链相邻两圈之间的停顿秒数(如外圈停-1后停顿一下再转中圈)")]
|
||
public float nextRingDelay = 0.3f; // 升级链圈间停顿
|
||
|
||
[Header("倍数显示(可选)")]
|
||
public TextMeshProUGUI tMP_BeiShu; // 倍数文本(转完后显示最终倍数)
|
||
public Text txt_BeiShu; // 倍数文本(转完后显示最终倍数)
|
||
|
||
private Tween _waiTween;
|
||
private Tween _zhongTween;
|
||
private Tween _neiTween;
|
||
|
||
/// <summary>三圈停靠值(0=不参与升级链持续慢转,-1=停在升级格,正值=停在该数值格):0外 1中 2内</summary>
|
||
private int[] _stopValues = new int[3];
|
||
/// <summary>最终倍数(服务端下发,直接显示,无加减计算)</summary>
|
||
private int _totalBeishu;
|
||
|
||
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);
|
||
|
||
// 座位上方定位(与 BJEndUI / MoveToSit 同一套座位坐标系):
|
||
// 转盘是 UI 大件,需要足够偏移避开炮台;2/3号座位在下方,偏移翻转向下
|
||
float y = seatOffsetY;
|
||
if (posID == 2 || posID == 3) y *= -1f;
|
||
transform.position = GetSeatPosition() + Vector3.up * y;
|
||
|
||
ParseDragonParam();
|
||
LogRings("Init");
|
||
|
||
// 音效:转盘出现(PW_Dial_Appear)
|
||
AudioManager.Instance.PlayerFXByName("PW_Dial_Appear");
|
||
|
||
StartCoroutine(RotateThenScore());
|
||
}
|
||
|
||
// ============================================================
|
||
#region 解析服务端参数
|
||
// ============================================================
|
||
|
||
/// <summary>
|
||
/// 解析最终倍数并自算三圈停靠路径(升级型,不依赖服务端 option)。
|
||
/// 最终倍数优先级:服务端 res.beizhu → 顶层 RoomKillNotice.beishu(Init 传入)→ 外圈随机正值兜底。
|
||
/// 停靠路径按“从内圈往外圈”规则自算,详见 ComputeStopPath。
|
||
/// </summary>
|
||
private void ParseDragonParam()
|
||
{
|
||
int target = 0;
|
||
if (obj != null)
|
||
{
|
||
try
|
||
{
|
||
JToken rootToken = obj is JToken t ? t : JToken.Parse(obj.ToString());
|
||
var dragon = BossKillParamParser.ParseDragon(rootToken);
|
||
if (dragon != null && dragon.res != null && dragon.res.beizhu > 0)
|
||
target = dragon.res.beizhu;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError($"[SLZP] 解析神龙转盘参数失败:{e.Message};原始={obj}");
|
||
}
|
||
}
|
||
|
||
if (target <= 0)
|
||
{
|
||
// res 为空或未下发 beizhu:用 Init 传入的顶层 beishu(RoomKillNotice.beishu)
|
||
target = bJbeishu;
|
||
}
|
||
if (target <= 0)
|
||
{
|
||
// 仍无数据:兜底随机一个外圈正值格
|
||
target = RandomPositiveValue(waiValues);
|
||
Debug.LogWarning($"[SLZP] 服务端未下发最终倍数,兜底随机 target={target}");
|
||
}
|
||
|
||
ComputeStopPath(target);
|
||
_totalBeishu = target;
|
||
Debug.Log($"[SLZP] 最终倍数={_totalBeishu} 停靠:外={_stopValues[0]} 中={_stopValues[1]} 内={_stopValues[2]}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从内圈往外圈自算停靠路径(升级型):
|
||
/// 1. 内圈表里有该倍数(如 10000/20000)→ 外圈、中圈都停 -1,内圈停该倍数;
|
||
/// 2. 中圈、外圈表里都有(如 300/500/600)→ 一半概率外圈直接停,一半概率外圈-1升级中圈停;
|
||
/// 3. 仅中圈有(如 800/1000)→ 外圈停 -1,中圈停该倍数;
|
||
/// 4. 仅外圈有(如 350/550/650/700)→ 外圈直接停该倍数。
|
||
/// 倍数不在任何表中时兜底随机外圈正值格。
|
||
/// </summary>
|
||
private void ComputeStopPath(int target)
|
||
{
|
||
bool inWai = IndexOfValue(waiValues, target) >= 0;
|
||
bool inZhong = IndexOfValue(zhongValues, target) >= 0;
|
||
bool inNei = IndexOfValue(neiValues, target) >= 0;
|
||
|
||
if (inNei)
|
||
{
|
||
_stopValues[0] = -1;
|
||
_stopValues[1] = -1;
|
||
_stopValues[2] = target;
|
||
}
|
||
else if (inZhong && inWai)
|
||
{
|
||
if (UnityEngine.Random.Range(0, 2) == 0)
|
||
{
|
||
_stopValues[0] = target; _stopValues[1] = 0; _stopValues[2] = 0;
|
||
}
|
||
else
|
||
{
|
||
_stopValues[0] = -1; _stopValues[1] = target; _stopValues[2] = 0;
|
||
}
|
||
}
|
||
else if (inZhong)
|
||
{
|
||
_stopValues[0] = -1; _stopValues[1] = target; _stopValues[2] = 0;
|
||
}
|
||
else if (inWai)
|
||
{
|
||
_stopValues[0] = target; _stopValues[1] = 0; _stopValues[2] = 0;
|
||
}
|
||
else
|
||
{
|
||
_stopValues[0] = RandomPositiveValue(waiValues);
|
||
_stopValues[1] = 0;
|
||
_stopValues[2] = 0;
|
||
Debug.LogWarning($"[SLZP] 倍数 {target} 不在三圈数值表中,兜底随机外圈停靠 {_stopValues[0]}");
|
||
}
|
||
}
|
||
|
||
/// <summary>数值在表中的索引;表为空或不在表中返回 -1</summary>
|
||
private int IndexOfValue(int[] table, int value)
|
||
{
|
||
return table == null || table.Length == 0 ? -1 : Array.IndexOf(table, value);
|
||
}
|
||
|
||
/// <summary>随机取表中一个非 -1(非升级格)的值;先随机试 8 次再线性兜底</summary>
|
||
private int RandomPositiveValue(int[] table)
|
||
{
|
||
if (table == null || table.Length == 0) return 0;
|
||
for (int i = 0; i < 8; i++)
|
||
{
|
||
int v = table[UnityEngine.Random.Range(0, table.Length)];
|
||
if (v >= 0) return v;
|
||
}
|
||
for (int i = 0; i < table.Length; i++)
|
||
if (table[i] >= 0) return table[i];
|
||
return 0;
|
||
}
|
||
|
||
#endregion
|
||
|
||
// ============================================================
|
||
#region 旋转流程
|
||
// ============================================================
|
||
|
||
/// <summary>
|
||
/// 打印三圈关键事实:停靠值、表长、每格角度、初始角度、父级旋转。
|
||
/// 用于排查"该停 0° 却停到别的格子"类错位。
|
||
/// </summary>
|
||
private void LogRings(string tag)
|
||
{
|
||
Transform[] rings = { wai, zhong, nei };
|
||
int[][] tables = { waiValues, zhongValues, neiValues };
|
||
string[] names = { "外圈", "中圈", "内圈" };
|
||
for (int i = 0; i < rings.Length; i++)
|
||
{
|
||
var r = rings[i];
|
||
if (r == null)
|
||
{
|
||
Debug.Log($"[SLZP][{tag}] {names[i]}: 未赋值");
|
||
continue;
|
||
}
|
||
int len = tables[i] != null ? tables[i].Length : 0;
|
||
float parentZ = r.parent != null ? r.parent.eulerAngles.z : 0f;
|
||
Debug.Log($"[SLZP][{tag}] {names[i]}({r.name}): 停靠值={_stopValues[i]} 表长={len} 每格={(len > 0 ? 360f / len : 0f):F1}° 初始localZ={r.localEulerAngles.z:F1}° 世界Z={r.eulerAngles.z:F1}° 父级Z={parentZ:F1}°");
|
||
}
|
||
}
|
||
|
||
/// <summary>转盘旋转完成后进入加分滚动</summary>
|
||
private IEnumerator RotateThenScore()
|
||
{
|
||
Transform[] rings = { wai, zhong, nei };
|
||
int[][] tables = { waiValues, zhongValues, neiValues };
|
||
|
||
if (rings[0] == null && rings[1] == null && rings[2] == null)
|
||
{
|
||
Debug.LogWarning("[SLZP] 三圈转盘均未赋值,跳过旋转直接加分");
|
||
yield return new WaitForSeconds(scoreStartDelay);
|
||
ShowBeishuUI();
|
||
yield return new WaitForSeconds(1f);
|
||
StartAddScore();
|
||
yield break;
|
||
}
|
||
|
||
// 1. 不停靠的圈(0=未停靠)先开始持续慢转(不停,直到爆奖结束回池)
|
||
for (int i = 0; i < rings.Length; i++)
|
||
{
|
||
if (rings[i] == null) continue;
|
||
if (_stopValues[i] == 0)
|
||
StartIdleSpin(i);
|
||
}
|
||
|
||
// 2. 参与的圈按 外→中→内 依次精确停靠(正点,无随机;0=不参与慢转,-1=停升级格)
|
||
for (int i = 0; i < rings.Length; i++)
|
||
{
|
||
if (rings[i] == null) continue;
|
||
if (_stopValues[i] == 0) continue;
|
||
|
||
bool done = false;
|
||
RotateToValue(i, tables[i], _stopValues[i], () => done = true);
|
||
yield return new WaitUntil(() => done);
|
||
|
||
// 停稳 → 激活该圈对应格的抽中效果(该圈其余格全部关闭)
|
||
ShowRingFx(i, tables[i], _stopValues[i]);
|
||
|
||
// 升级链:该圈停稳后、下一参与圈开转前的停顿(如外圈停-1后顿一下再转中圈)
|
||
if (nextRingDelay > 0 && HasLaterStop(rings, i))
|
||
yield return new WaitForSeconds(nextRingDelay);
|
||
}
|
||
|
||
// 3. 显示最终倍数
|
||
ShowBeishuUI();
|
||
|
||
// 4. 转完后延迟再加分 → MoveToSit → OnScoreEnd → JiaFen → die
|
||
if (scoreStartDelay > 0)
|
||
yield return new WaitForSeconds(scoreStartDelay);
|
||
|
||
StartAddScore();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 神龙转盘:总分巨大(如 2000 万),基类 AddScoreRoutine 是逐帧加底分模式
|
||
/// (Random.Range(paoBei, paoBei*2)),paoBei 为 0 时直接死循环、分数也永远滚不完,
|
||
/// 导致 MoveToSit → OnScoreEnd → ShowBJEndUI 全被卡住(EndUI 出不来)。
|
||
/// 改用基类 RollNumber 一秒内快速滚动到总分。
|
||
/// </summary>
|
||
protected override IEnumerator AddScoreRoutine()
|
||
{
|
||
if (tMP_Score != null)
|
||
{
|
||
bool done = false;
|
||
RollNumber(v => tMP_Score.text = v.ToString(), 0, maxScore, 1f, () => done = true);
|
||
yield return new WaitUntil(() => done);
|
||
yield return new WaitForSeconds(0.5f);
|
||
}
|
||
|
||
// 加分完毕 → 分数版飞回座位 → 结束后 JiaFen → ShowBJEndUI → die
|
||
MoveToSit();
|
||
}
|
||
|
||
/// <summary>显示最终倍数:直接输出服务端下发的数字,不做任何计算;兼容 TMP 与旧版 UGUI Text</summary>
|
||
private void ShowBeishuUI()
|
||
{
|
||
// 音效:转盘展示(PW_Dial_Show)
|
||
AudioManager.Instance.PlayerFXByName("PW_Dial_Show");
|
||
|
||
if (tMP_BeiShu != null)
|
||
{
|
||
tMP_BeiShu.text = _totalBeishu.ToString();
|
||
tMP_BeiShu.gameObject.SetActive(true);
|
||
}
|
||
if (txt_BeiShu != null)
|
||
{
|
||
txt_BeiShu.text = _totalBeishu.ToString();
|
||
txt_BeiShu.gameObject.SetActive(true);
|
||
}
|
||
Debug.Log($"[SLZP] 显示最终倍数:{_totalBeishu}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按数值停靠指定圈:数值 → 格子索引 → 精确角度(索引 × 360/格子数),无随机。
|
||
/// </summary>
|
||
private void RotateToValue(int ringIndex, int[] table, int value, Action onComplete)
|
||
{
|
||
Transform circle = GetRing(ringIndex);
|
||
if (circle == null)
|
||
{
|
||
onComplete?.Invoke();
|
||
return;
|
||
}
|
||
|
||
float dir = GetDir(ringIndex);
|
||
int slot = FindSlotIndex(table, value);
|
||
// 正点停靠:格子中心角度 = 索引 × 每格角度,精确无随机
|
||
float targetAngle = slot * (360f / (table.Length > 0 ? table.Length : 1));
|
||
|
||
string ringName = ringIndex == 0 ? "外圈" : ringIndex == 1 ? "中圈" : "内圈";
|
||
float curr = circle.localRotation.eulerAngles.z;
|
||
Debug.Log($"[SLZP] {ringName} 开始旋转: value={value} slot={slot} 当前={curr:F1}° 目标={targetAngle}° dir={dir} 表长={table.Length} 每格={(360f / (table.Length > 0 ? table.Length : 1)):F1}°");
|
||
|
||
// 音效:转盘旋转(PW_Dial_Rotate)
|
||
AudioManager.Instance.PlayerFXByName("PW_Dial_Rotate");
|
||
|
||
// 同向到目标的角度差(已带方向符号)
|
||
float deltaToTarget = AngleDiff(curr, targetAngle, dir);
|
||
// 总增量 = N圈 + 到目标的差值,保证转 N 圈再停在目标
|
||
float totalDelta = dir * spinRounds * 360f + deltaToTarget;
|
||
|
||
// LocalAxisAdd 增量旋转,不取最短路径,保证圈数和方向
|
||
Tween tween = circle.DOLocalRotate(new Vector3(0, 0, totalDelta), rotateDuration, RotateMode.LocalAxisAdd);
|
||
tween.SetEase(Ease.OutCubic);
|
||
tween.OnComplete(() =>
|
||
{
|
||
// 强制校正到精确目标角度,消除浮点误差
|
||
circle.localRotation = Quaternion.Euler(0, 0, targetAngle);
|
||
float actual = circle.localRotation.eulerAngles.z;
|
||
Debug.Log($"[SLZP] {ringName} 停靠完成: 实际={actual}° 目标={targetAngle}°");
|
||
SetTween(ringIndex, null);
|
||
onComplete?.Invoke();
|
||
});
|
||
|
||
SetTween(ringIndex, tween);
|
||
}
|
||
|
||
/// <summary>判断 ringIndex 之后是否还有参与停靠的圈(用于升级链圈间停顿)</summary>
|
||
private bool HasLaterStop(Transform[] rings, int ringIndex)
|
||
{
|
||
for (int i = ringIndex + 1; i < rings.Length; i++)
|
||
{
|
||
if (rings[i] != null && _stopValues[i] != 0) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>未停靠的圈持续慢转(线性循环,直到销毁清理)</summary>
|
||
private void StartIdleSpin(int ringIndex)
|
||
{
|
||
Transform circle = GetRing(ringIndex);
|
||
if (circle == null) return;
|
||
|
||
KillTween(ringIndex);
|
||
Debug.Log($"[SLZP] 圈{ringIndex} 慢转启动: localZ={circle.localEulerAngles.z:F1}° 世界Z={circle.eulerAngles.z:F1}°");
|
||
Tween tween = circle.DOLocalRotate(new Vector3(0, 0, GetDir(ringIndex) * 360f), idleSpinDuration, RotateMode.LocalAxisAdd);
|
||
tween.SetEase(Ease.Linear);
|
||
tween.SetLoops(-1, LoopType.Restart);
|
||
SetTween(ringIndex, tween);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停稳后激活该圈对应格的抽中效果(纯 SetActive 切换);
|
||
/// 该圈其余格全部关闭。路径上的升级格(-1)同样会亮,展示完整中奖路径。
|
||
/// </summary>
|
||
private void ShowRingFx(int ringIndex, int[] table, int value)
|
||
{
|
||
var fx = GetRingFx(ringIndex);
|
||
if (fx == null || fx.Length == 0) return;
|
||
|
||
int slot = FindSlotIndex(table, value);
|
||
for (int i = 0; i < fx.Length; i++)
|
||
{
|
||
if (fx[i] == null) continue;
|
||
fx[i].SetActive(i == slot);
|
||
}
|
||
string ringName = ringIndex == 0 ? "外圈" : ringIndex == 1 ? "中圈" : "内圈";
|
||
Debug.Log($"[SLZP] {ringName} 亮格: slot={slot} value={value}");
|
||
}
|
||
|
||
/// <summary>圈索引 → 抽中效果数组</summary>
|
||
private GameObject[] GetRingFx(int ringIndex)
|
||
{
|
||
switch (ringIndex)
|
||
{
|
||
case 0: return waiFx;
|
||
case 1: return zhongFx;
|
||
default: return neiFx;
|
||
}
|
||
}
|
||
|
||
/// <summary>关闭三圈全部抽中效果</summary>
|
||
private void HideAllRingFx()
|
||
{
|
||
HideRingFx(waiFx);
|
||
HideRingFx(zhongFx);
|
||
HideRingFx(neiFx);
|
||
}
|
||
|
||
private void HideRingFx(GameObject[] fx)
|
||
{
|
||
if (fx == null) return;
|
||
for (int i = 0; i < fx.Length; i++)
|
||
if (fx[i] != null) fx[i].SetActive(false);
|
||
}
|
||
|
||
/// <summary>数值 → 格子索引;找不到返回 0 并警告(兜底停第一格)</summary>
|
||
private int FindSlotIndex(int[] table, int value)
|
||
{
|
||
if (table == null || table.Length == 0) return 0;
|
||
int idx = Array.IndexOf(table, value);
|
||
if (idx < 0)
|
||
{
|
||
Debug.LogWarning($"[SLZP] 数值 {value} 不在数值表中,兜底停索引0");
|
||
idx = 0;
|
||
}
|
||
return idx;
|
||
}
|
||
|
||
/// <summary>圈索引 → Transform</summary>
|
||
private Transform GetRing(int ringIndex)
|
||
{
|
||
switch (ringIndex)
|
||
{
|
||
case 0: return wai;
|
||
case 1: return zhong;
|
||
default: return nei;
|
||
}
|
||
}
|
||
|
||
/// <summary>圈索引 → 旋转方向</summary>
|
||
private float GetDir(int ringIndex)
|
||
{
|
||
switch (ringIndex)
|
||
{
|
||
case 0: return waiDir;
|
||
case 1: return zhongDir;
|
||
default: return neiDir;
|
||
}
|
||
}
|
||
|
||
/// <summary>圈索引 → Tween</summary>
|
||
private void SetTween(int ringIndex, Tween tween)
|
||
{
|
||
switch (ringIndex)
|
||
{
|
||
case 0: _waiTween = tween; break;
|
||
case 1: _zhongTween = tween; break;
|
||
default: _neiTween = tween; break;
|
||
}
|
||
}
|
||
|
||
/// <summary>圈索引 → 杀掉残留 Tween</summary>
|
||
private void KillTween(int ringIndex)
|
||
{
|
||
switch (ringIndex)
|
||
{
|
||
case 0: _waiTween?.Kill(); _waiTween = null; break;
|
||
case 1: _zhongTween?.Kill(); _zhongTween = null; break;
|
||
default: _neiTween?.Kill(); _neiTween = null; break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算从 curr 到 target 的同向最短角度差。
|
||
/// dir>0(顺时针):diff ∈ [0, 360)
|
||
/// dir<0(逆时针):diff ∈ (-360, 0]
|
||
/// </summary>
|
||
private float AngleDiff(float curr, float target, float dir)
|
||
{
|
||
float diff = (target - curr) % 360f;
|
||
if (diff < 0) diff += 360f; // 归一化到 [0, 360)
|
||
if (dir < 0 && diff > 0) diff -= 360f; // 逆时针取负值
|
||
return diff;
|
||
}
|
||
|
||
#endregion
|
||
|
||
// ============================================================
|
||
#region 定位(重写基类,禁止脱父级)
|
||
// ============================================================
|
||
|
||
/// <summary>
|
||
/// 重写基类 ApplySeatOffset:基类在预制体根节点无 RectTransform 时会
|
||
/// transform.SetParent(null) 把特效从 UI 下拽到场景根节点,
|
||
/// 导致“勾了 isToUI 也没挂在 UI 上”。这里只缓存座位引用,
|
||
/// 位置统一由 Init 中座位上方偏移逻辑处理,绝不脱父级。
|
||
/// </summary>
|
||
protected override void ApplySeatOffset()
|
||
{
|
||
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null) return;
|
||
var sits = CreateFishManager.Instance.currGameType.list_Sits;
|
||
if (posID >= 0 && posID < sits.Count && sits[posID] != null)
|
||
_targetSit = sits[posID];
|
||
}
|
||
|
||
/// <summary>
|
||
/// 对象池复用前重置:杀掉三圈残留 Tween(防复用时还在转)。
|
||
/// </summary>
|
||
protected override void ResetState()
|
||
{
|
||
base.ResetState();
|
||
KillTween(0);
|
||
KillTween(1);
|
||
KillTween(2);
|
||
HideAllRingFx();
|
||
_stopValues = new int[3];
|
||
_totalBeishu = 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 结束时播放结算语音(时来运转,PW_Settle_Dial),
|
||
/// 其余走基类(回加金币 + bjEndUI + 清面板 + die)。
|
||
/// </summary>
|
||
protected override void OnScoreEnd()
|
||
{
|
||
if (isScoreEnd) return;
|
||
|
||
// 音效:结算转盘——时来运转语音(PW_Settle_Dial)
|
||
AudioManager.Instance.PlayerFXByName("PW_Settle_Dial");
|
||
|
||
base.OnScoreEnd();
|
||
}
|
||
|
||
/// <summary>清理三圈 Tween 后再走基类清理</summary>
|
||
protected override void CleanupBeforeDie()
|
||
{
|
||
KillTween(0);
|
||
KillTween(1);
|
||
KillTween(2);
|
||
base.CleanupBeforeDie();
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
_waiTween?.Kill();
|
||
_zhongTween?.Kill();
|
||
_neiTween?.Kill();
|
||
}
|
||
|
||
#endregion
|
||
} |