Files
5.24BuYu/Assets/MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs
T
2026-06-02 21:54:24 +08:00

309 lines
11 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 System.Collections.Generic;
using TMPro;
using UnityEngine;
/// <summary>
/// Boss 爆奖事件基类
/// 完整流程:死亡特效 → EffEnd → MoveToSit → 滚动加分(期间可多次 CallBJ 发红包) → JiaFen → die
/// </summary>
public class BJEventBase : MonoBehaviour
{
// ==================== Inspector 字段 ====================
[Header("分数")]
public TextMeshProUGUI tMP_Score; // 分数显示文本(空则自动从预制体创建)
public GameObject scorePanelPrefab; // 分数版预制体(优先;空则用 Manager 自带 dieFXPrefabAwardTmp)
public int currScore; // 当前显示分数
public int maxScore; // 最终总分
[Header("红包")]
public LayeredPool layeredPool; // 红包分层对象池
public int scoreCount; // 红包分包数量(每次 CallBJ 发几个红包)
[Header("玩家")]
public int posID; // 击杀者座位ID
public int paoBei; // 炮倍
[Header("移动")]
public float moveDuration = 0.5f; // UI 移动到座位的时间
public Ease moveEase = Ease.OutQuad; // 移动缓动曲线
public Vector3 startOffset = new Vector3(0, 0, -100); // 起始位置偏移(归零后再加此值,可手调)
[Header("加分")]
public float addScoreDuration = 0.5f; // 加分滚动持续时间
// ==================== 回调 ====================
public Action JiaFen; // 加分完成回调(回加到玩家金币)
// ==================== 归属 ====================
public bool isSelf; // 是否是自己打出的爆奖(非自己只播特效不加分)
// ==================== 运行时状态 ====================
public int totalBJCount; // 计划爆奖总次数(由 boss 设置)
public int currBJCount; // 已爆奖次数
public bool isEffEnd; // 特效阶段已结束
public bool isScoreStart; // 加分阶段已开始
public bool isScoreEnd; // 加分阶段已结束
public bool isGoldEffectStart; // 红包特效阶段已开始
private SitPosData _targetSit; // 目标座位引用
private Coroutine _scoreCoroutine; // 加分协程
// ==================== 生命周期 ====================
private void Start()
{
}
// ==================== 初始化 ====================
/// <summary>
/// 初始化爆奖参数。由 Boss 的 DieFish → action_effect_DieAward 回调中调用。
/// </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(int goldCount, int posID, int paobei, Action<int> action, Action action1 = null)
{
JiaFen = () => { action?.Invoke(0); };
maxScore = goldCount;
this.posID = posID;
paoBei = paobei;
// 自动检测:tMP_Score 为空则按优先级创建分数版
EnsureScoreBoard();
// 初始位置:座位坐标 + 手调偏移
ApplySeatOffset();
// 是否是本地玩家自己打的
isSelf = _targetSit != null && _targetSit.user == GameManager.Instance.user.id;
action1?.Invoke();
}
/// <summary>
/// 自动补充分数版:tMP_Score 为空 → 优先用 scorePanelPrefab → 否则用 Manager 的 dieFXPrefabAwardTmp
/// 父对象挂在 CreateFishManager.Instance.currGameType.subPanelParent 下
/// </summary>
protected virtual void EnsureScoreBoard()
{
if (tMP_Score != null) return;
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null) return;
var parent = CreateFishManager.Instance.currGameType.subPanelParent;
if (parent == null) return;
// 1. 优先用 Inspector 设置的预制体
GameObject prefab = scorePanelPrefab;
// 2. 否则用 Manager 自带的 dieFXPrefabAwardTmp
if (prefab == null)
prefab = CreateFishManager.Instance.dieFXPrefabAwardTmp;
if (prefab == null) return;
var board = Instantiate(prefab, parent);
board.transform.position = transform.position;
var tmp = board.GetComponentInChildren<TextMeshProUGUI>();
if (tmp != null) tMP_Score = tmp;
}
// ==================== 特效相关 ====================
/// <summary>死亡特效阶段结束回调(由动画事件/子类调用)</summary>
public virtual void EffEnd()
{
if (isEffEnd) return;
isEffEnd = true;
MoveToSit();
}
/// <summary>触发红包特效(可在子类 Update/动画事件中重复调用)</summary>
public virtual void GoldEffect()
{
BigPrize();
}
// ==================== 移动到座位 ====================
/// <summary>将 UI 定位到座位坐标 + startOffset(在 Inspector 中手动调偏移)</summary>
/// <summary>
/// 设置爆奖初始位置:RectTransform → UI 画布中间;普通 Transform → 场景原点 (0,0,0)
/// </summary>
private void ApplySeatOffset()
{
// 判断类型,确定基础位置
var rect = GetComponent<RectTransform>();
if (rect != null)
{
// UI 元素 → 画布中间
var canvas = GetComponentInParent<Canvas>();
if (canvas != null && canvas.renderMode != RenderMode.WorldSpace)
{
// ScreenSpace → 屏幕中间转世界坐标
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
{
// WorldSpace 或无 Canvas → 归零加偏移
transform.position = Vector3.zero + startOffset;
}
}
else
{
transform.SetParent(null);
// 普通 3D Transform → 场景原点
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>将爆奖 UI 从当前位置移动到击杀者座位</summary>
public virtual void MoveToSit()
{
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null)
{
OnMoveComplete();
return;
}
var sits = CreateFishManager.Instance.currGameType.list_Sits;
if (posID < 0 || posID >= sits.Count || sits[posID] == null)
{
OnMoveComplete();
return;
}
_targetSit = sits[posID];
Transform sitTransform = _targetSit.transform;
// 获取座位上的目标位置(优先用当前炮台位置)
Vector3 targetPos = sitTransform.position;
if (_targetSit.currentTurret != null)
{
targetPos = _targetSit.currentTurret.transform.position;
}
// DOTween 移动到座位
transform.DOMove(targetPos, moveDuration)
.SetEase(moveEase)
.OnComplete(() =>
{
OnMoveComplete();
});
}
/// <summary>移动到座位完成 → 开始加分</summary>
protected virtual void OnMoveComplete()
{
isScoreStart = true;
StartAddScore();
}
// ==================== 爆奖(发红包) ====================
/// <summary>
/// 执行一次爆奖(发红包)。可在动画事件中多次调用。
/// 每次调用会通过 LayeredPool 分发金币红包。
/// </summary>
/// <param name="minCount">每次最小红包数</param>
/// <param name="maxCount">每次最大红包数</param>
public virtual void CallBJ(int minCount = 10, int maxCount = 15)
{
if (isScoreEnd) return;
BigPrize(minCount, maxCount);
currBJCount++;
// 达到总次数 → 标记爆奖结束
if (totalBJCount > 0 && currBJCount >= totalBJCount)
{
isGoldEffectStart = false;
}
}
/// <summary>
/// 包一个红包分层
/// </summary>
public virtual List<RedPacketRecord> BigPrize(int min = 10, int max = 15)
{
if (layeredPool == null)
layeredPool = new LayeredPool(maxScore, scoreCount > 0 ? scoreCount : 1);
var v = layeredPool.BossGlodCoinRandrom(
tMP_Score != null ? tMP_Score.transform.position : transform.position,
min, max);
return v;
}
// ==================== 加分滚动 ====================
/// <summary>开始加分滚动动画(子类可 override 自定义)</summary>
public virtual void StartAddScore()
{
if (_scoreCoroutine != null)
StopCoroutine(_scoreCoroutine);
_scoreCoroutine = StartCoroutine(AddScoreRoutine());
}
/// <summary>默认加分滚动协程</summary>
protected virtual IEnumerator AddScoreRoutine()
{
// 根据炮倍计算每次步进值
int stepBase = Mathf.Max(1, paoBei / 10);
float elapsed = 0f;
while (elapsed < addScoreDuration && currScore < maxScore)
{
int step = UnityEngine.Random.Range(stepBase, stepBase * 5);
currScore = Mathf.Min(currScore + step, maxScore);
if (tMP_Score != null)
tMP_Score.text = currScore.ToString();
elapsed += Time.deltaTime * 0.2f; // 控制滚动速度
yield return null;
}
// 最终值
currScore = maxScore;
if (tMP_Score != null)
tMP_Score.text = maxScore.ToString();
OnScoreEnd();
}
/// <summary>加分完成</summary>
protected virtual void OnScoreEnd()
{
if (isScoreEnd) return;
isScoreEnd = true;
JiaFen?.Invoke();
// 延迟一会儿再销毁,让玩家看一下
Invoke(nameof(die), 0.5f);
}
// ==================== 销毁 ====================
public virtual void die()
{
transform.DOScale(Vector3.zero, 0.5f).OnComplete(() =>
{
Destroy(gameObject);
});
}
}