227 lines
8.9 KiB
C#
227 lines
8.9 KiB
C#
using DG.Tweening;
|
||
using System;
|
||
using System.Collections;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// Boss 爆奖事件基类(骨架)。
|
||
/// 只保留所有爆奖形态共用的部分:
|
||
/// 1. 参数初始化(金币/座位/炮倍/底分/倍数)与座位归属(isSelf)
|
||
/// 2. 结束流程:OnScoreEnd → JiaFen(回加金币)→ ShowBJEndUI(结算面板)→ die
|
||
/// 3. 通用工具:GetSeatPosition / ShrinkEffect / RollNumber(数字滚动)
|
||
///
|
||
/// 爆奖形态与继承层级:
|
||
/// 1. 积分型(分红包 n 次加积分)→ BJRedPacketEvent:红包分包、金币逐个累分、分数面板、滚分、飞回座位
|
||
/// 2. 倍数型(分 n 次加爆奖倍数)→ 多数直接继承 BJRedPacketEvent(复用结算与分数面板),倍数文本各自管理;
|
||
/// FLXJ / GSL 这类 Timeline 累倍数玩法继承 TimelineBeiShuEvent
|
||
/// </summary>
|
||
public class BJEventBase : MonoBehaviour
|
||
{
|
||
[Header("结算")]
|
||
public BJEndUI bjEndUI; // 爆奖结算面板预制体
|
||
public float bjEndUIOffsetY = 150f; // BJEndUI 在座位上方偏移
|
||
|
||
[Header("玩家参数")]
|
||
public int posID; // 击杀者座位ID
|
||
public int paoBei; // 炮倍
|
||
public int fishScore; // 底分
|
||
public int bJbeishu; // 爆奖倍数
|
||
public int maxScore; // 最终总分
|
||
|
||
// ==================== 回调 / 归属 ====================
|
||
public Action JiaFen; // 加分完成回调(回加到玩家金币)
|
||
public bool isSelf; // 是否是自己打出的爆奖(非自己只播特效不加分)
|
||
public object obj; // 服务端下发参数(RoomKillNotice.param)
|
||
|
||
// ==================== 运行时状态 ====================
|
||
public bool isScoreEnd; // 结束流程已触发(OnScoreEnd 防重入)
|
||
|
||
protected SitPosData _targetSit; // 目标座位引用
|
||
|
||
private Coroutine _rollCoroutine; // 当前数字滚动协程(RollNumber 防重复启动)
|
||
|
||
// ==================== 初始化 ====================
|
||
/// <summary>
|
||
/// 初始化爆奖参数。由 Boss 的 DieFish → action_effect_DieAward 回调中调用。
|
||
/// ⭐ 对象池复用安全:每次 Init 重置所有运行时状态,避免上次爆奖残留导致下次流程跳过
|
||
/// </summary>
|
||
/// <param name="goldCount">服务器返回的总金币</param>
|
||
/// <param name="posID">击杀者座位 ID</param>
|
||
/// <param name="paobei">炮倍</param>
|
||
/// <param name="action">最终加分回调(回加到玩家金币)</param>
|
||
/// <param name="action1">初始化完成后的附加回调(如设置龙珠值)</param>
|
||
public virtual void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
|
||
{
|
||
// ⭐ 重置运行时状态(对象池复用的爆奖对象会残留上次状态,导致 OnScoreEnd 等直接 return)
|
||
ResetState();
|
||
|
||
JiaFen = () => { action?.Invoke(0); };
|
||
maxScore = (int)goldCount;
|
||
this.posID = posID;
|
||
this.fishScore = (int)fishScore;
|
||
paoBei = (int)paobei;
|
||
bJbeishu = beishu;
|
||
|
||
// 初始位置不手动设置:位置和大小完全用预制体里配置好的(缓存座位引用)
|
||
ApplySeatOffset();
|
||
|
||
// 是否是本地玩家自己打的
|
||
isSelf = _targetSit != null && _targetSit.user == GameManager.Instance.user.id;
|
||
|
||
action1?.Invoke();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置所有运行时状态(对象池复用时调用,避免上次爆奖残留导致下次流程异常)。
|
||
/// 子类 override 必须调用 base.ResetState()。
|
||
/// </summary>
|
||
protected virtual void ResetState()
|
||
{
|
||
isScoreEnd = false;
|
||
maxScore = 0;
|
||
_targetSit = null;
|
||
obj = null;
|
||
|
||
// 停止所有残留协程
|
||
StopAllCoroutines();
|
||
_rollCoroutine = null;
|
||
}
|
||
|
||
// ==================== 定位 ====================
|
||
/// <summary>
|
||
/// ⭐ 爆奖初始位置不手动设置:位置和大小完全用预制体里配置好的,代码不去调整
|
||
/// (z 也用预制体自带的,不再被 startOffset 推到 -100 那么深)。
|
||
/// 只缓存座位引用(isSelf 判定与 GetSeatPosition/MoveToSit/结算定位依赖)。
|
||
/// </summary>
|
||
protected virtual void ApplySeatOffset()
|
||
{
|
||
GetSeatPosition();
|
||
}
|
||
|
||
/// <summary>获取座位坐标</summary>
|
||
public Vector3 GetSeatPosition()
|
||
{
|
||
if (_targetSit != null)
|
||
{
|
||
if (_targetSit.currentTurret != null)
|
||
return _targetSit.currentTurret.transform.position;
|
||
return _targetSit.transform.position;
|
||
}
|
||
if (CreateFishManager.Instance != null && CreateFishManager.Instance.currGameType != null)
|
||
{
|
||
var sits = CreateFishManager.Instance.currGameType.list_Sits;
|
||
if (posID >= 0 && posID < sits.Count && sits[posID] != null)
|
||
{
|
||
_targetSit = sits[posID];
|
||
if (_targetSit.currentTurret != null)
|
||
return _targetSit.currentTurret.transform.position;
|
||
return _targetSit.transform.position;
|
||
}
|
||
}
|
||
return transform.position;
|
||
}
|
||
|
||
// ==================== 结束流程 ====================
|
||
/// <summary>加分完成——回加金币、显示结束UI、销毁自身。子类可 override 扩展(需调用 base)。</summary>
|
||
protected virtual void OnScoreEnd()
|
||
{
|
||
if (isScoreEnd) return;
|
||
isScoreEnd = true;
|
||
|
||
// 回加金币到玩家
|
||
JiaFen?.Invoke();
|
||
|
||
// BJEndUI:无论是否开启分数面板都显示
|
||
ShowBJEndUI();
|
||
|
||
// 销毁爆奖对象自身
|
||
die();
|
||
}
|
||
|
||
/// <summary>创建爆奖结算面板(统一入口:所有子类不要各自 Instantiate bjEndUI)。</summary>
|
||
protected void ShowBJEndUI()
|
||
{
|
||
if (bjEndUI == null) return;
|
||
|
||
var uiPos = GetBJEndUIPosition();
|
||
var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, GetBJEndUIParent());
|
||
endUI.Init(bJbeishu, maxScore, isSelf);
|
||
}
|
||
|
||
/// <summary>
|
||
/// bjEndUI 的父对象:直接挂击杀者玩家所在座位(SitPosData,UI 游戏座位层),
|
||
/// 随座位/UI 卸载自动清理;找不到击杀者座位时回退 bjEffectRoot。
|
||
/// </summary>
|
||
protected Transform GetBJEndUIParent()
|
||
{
|
||
if (_targetSit != null && _targetSit.transform != null)
|
||
return _targetSit.transform;
|
||
return CreateFishManager.Instance.bjEffectRoot;
|
||
}
|
||
|
||
/// <summary>BJEndUI 的生成位置:默认座位上方(2/3 号座位翻转到下方)。子类可 override。</summary>
|
||
protected virtual Vector3 GetBJEndUIPosition()
|
||
{
|
||
float y = bjEndUIOffsetY;
|
||
if (posID == 2 || posID == 3) y *= -1f;
|
||
return GetSeatPosition() + Vector3.up * y;
|
||
}
|
||
|
||
// ==================== 通用数字滚动 ====================
|
||
/// <summary>
|
||
/// 数字滚动:从 from 每帧插值到 to,通过 onValue 回调当前值(供倍数滚动/分数滚动复用)。
|
||
/// 自动停止上一次未完成的滚动,防止动画叠加;duration<=0 或 to<=from 时直接落值。
|
||
/// </summary>
|
||
protected void RollNumber(Action<int> onValue, int from, int to, float duration, Action onDone = null)
|
||
{
|
||
if (_rollCoroutine != null)
|
||
StopCoroutine(_rollCoroutine);
|
||
_rollCoroutine = StartCoroutine(RollNumberRoutine(onValue, from, to, duration, onDone));
|
||
}
|
||
|
||
private IEnumerator RollNumberRoutine(Action<int> onValue, int from, int to, float duration, Action onDone)
|
||
{
|
||
if (duration <= 0f || to <= from)
|
||
{
|
||
onValue?.Invoke(to);
|
||
onDone?.Invoke();
|
||
_rollCoroutine = null;
|
||
yield break;
|
||
}
|
||
|
||
float elapsed = 0f;
|
||
while (elapsed < duration)
|
||
{
|
||
elapsed += Time.deltaTime;
|
||
float t = Mathf.Clamp01(elapsed / duration);
|
||
onValue?.Invoke(Mathf.RoundToInt(Mathf.Lerp(from, to, t)));
|
||
yield return null;
|
||
}
|
||
|
||
onValue?.Invoke(to);
|
||
onDone?.Invoke();
|
||
_rollCoroutine = null;
|
||
}
|
||
|
||
// ==================== 销毁 ====================
|
||
/// <summary>缩小隐藏爆奖本体(不影响分数面板)</summary>
|
||
public virtual void ShrinkEffect()
|
||
{
|
||
transform.DOScale(Vector3.zero, 0.5f);
|
||
}
|
||
|
||
/// <summary>停止协程并清理派生资源(子类 override 必须调用 base)。</summary>
|
||
protected virtual void CleanupBeforeDie()
|
||
{
|
||
// 停止所有协程(防止 SetActive(false) 后协程残留)
|
||
StopAllCoroutines();
|
||
}
|
||
|
||
/// <summary>销毁自身 GameObject(先清理派生资源)</summary>
|
||
public virtual void die()
|
||
{
|
||
CleanupBeforeDie();
|
||
Destroy(gameObject);
|
||
}
|
||
}
|