Files
5.24BuYu/Assets/MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs
T
2026-08-22 17:23:07 +08:00

243 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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; // 最终总分
[Header("位置")]
public Vector3 startOffset = new Vector3(0, 0, -100); // 爆奖对象初始位置偏移
// ==================== 回调 / 归属 ====================
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>
/// 设置爆奖初始位置:RectTransform → UI 画布中间;普通 Transform → 场景原点 (0,0,0)
/// </summary>
protected virtual void ApplySeatOffset()
{
var rect = GetComponent<RectTransform>();
if (rect != null)
{
var canvas = GetComponentInParent<Canvas>();
if (canvas != null && canvas.renderMode != RenderMode.WorldSpace)
{
Vector2 screenCenter = new Vector2(Screen.width / 2f, Screen.height / 2f);
RectTransformUtility.ScreenPointToWorldPointInRectangle(
canvas.GetComponent<RectTransform>(), screenCenter, canvas.worldCamera, out Vector3 worldPos);
transform.position = worldPos + startOffset;
}
else
{
transform.position = Vector3.zero + startOffset;
}
}
else
{
transform.SetParent(null);
transform.position = Vector3.zero + startOffset;
}
// 缓存座位引用
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>获取座位坐标</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, CreateFishManager.Instance.bjEffectRoot);
endUI.Init(bJbeishu, maxScore, isSelf);
}
/// <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);
}
}