1309 lines
56 KiB
C#
1309 lines
56 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Threading.Tasks;
|
||
using asap.core;
|
||
using cfg;
|
||
using DG.Tweening;
|
||
using game;
|
||
using GameCore;
|
||
using TMPro;
|
||
using UI.Wheel;
|
||
using UniRx;
|
||
using UnityEngine;
|
||
using UnityEngine.Playables;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||
using Random = UnityEngine.Random;
|
||
|
||
namespace EventBossFight
|
||
{
|
||
public partial class EventBossFightMainPanel : BasePanel
|
||
{
|
||
#region UI_ELEMENTS
|
||
private PlayableDirector _enterDirector;
|
||
//top
|
||
private RewardItemNew[] _bossReward;
|
||
private TMP_Text _textBossHp;
|
||
private Image _imgBossHpBar;
|
||
private GameObject _hpBossObj;
|
||
private RewardItemNew _bossRewardFinal;
|
||
private TMP_Text _textBossHpFinal;
|
||
private Image _imgBossHpBarFinal;
|
||
private GameObject _hpBossObjFinal;
|
||
|
||
private RewardItemNew _finalReward;
|
||
private TMP_Text _textTime;
|
||
private SandDigLevel[] _levels;
|
||
private Button _btnQuestionmark;
|
||
private GameObject _goBtnFightInfo;
|
||
private Button _btnFightInfo;
|
||
private TMP_Text _textBossAttackTime;
|
||
private TMP_Text _textBossAttackRange;
|
||
private GameObject _objTipsBoss;
|
||
|
||
//center
|
||
/// <summary>Boss 预制体父节点(仅挂载 Transform,不要求根上 <see cref="PlayableDirector"/>)。</summary>
|
||
protected Transform _bossMount;
|
||
private PlayableDirector _playerDirector;
|
||
private EventBossFightTimelinePlayerCell _playerCell;
|
||
//bottom
|
||
private Button _btnAdd;
|
||
private Button _btnSpin;
|
||
private Button _btnClose;
|
||
private Button _btnMagnification;
|
||
private TMP_Text _textMagnification;
|
||
private GameObject _objMagnification;
|
||
private TMP_Text _textPlayerHp;
|
||
private TMP_Text _textPlayerChangeHp;
|
||
private RectTransform _iconHpTarget;
|
||
private Button _iconHpBtn;
|
||
private GameObject _tipsHp;
|
||
private Button _tipsHpBtnClose;
|
||
private Image _imgPlayerHpBar;
|
||
private Image[] _shields;
|
||
private Button[] _shieldBtns;
|
||
private GameObject _tipsShield;
|
||
private Button _tipsShieldBtnClose;
|
||
private TMP_Text _textSpin;
|
||
private TMP_Text _textTokenAmount;
|
||
private Image _imgTokenIcon;
|
||
private EventBossFightWheelRewardComponent _wheel;
|
||
private RewardFlyBatchController RewardFlyBatchCtrl;
|
||
/// <summary>付费复活:与转盘区域互斥,预制体上需有名为 btn_revive 的节点。</summary>
|
||
private GameObject _goPaidReviveRoot;
|
||
private GameObject _goSpinButtonRoot;
|
||
private GameObject _goMagnificationRoot;
|
||
private Button _btnPaidRevive;
|
||
private TMP_Text _textPaidRevivePrice;
|
||
//UI effect
|
||
private Animation _shieldAddAni;
|
||
private Animation _hpAddAni;
|
||
private GameObject _tokenShieldGameObject;
|
||
private GameObject _tokenHpGameObject;
|
||
//private Animation _tokenAddAni;
|
||
#endregion UI_ELEMENTS
|
||
|
||
#region FX
|
||
|
||
private GameObject fx_eventbossfight_warning;
|
||
private GameObject fx_eventbossfight_wheel_shieldswitch;
|
||
private GameObject fx_eventbossfight_wheel_healswitch;
|
||
private GameObject fx_eventbossfight_wheel_heal_01;
|
||
private GameObject fx_eventbossfight_wheel_heal_02;
|
||
#endregion
|
||
|
||
#region SerializeField
|
||
[Header("UI Effect")]
|
||
[SerializeField] [Min(0)]private float delayShowFailPanelTime=0.5f;
|
||
[SerializeField] [Min(0)] private float sliderChangeTime = 0.3f;
|
||
[SerializeField] [Min(0)] private float hpTextChangeTime = 1f;
|
||
[SerializeField] [Min(0)] private float panelOutAniTime = 0.3f;
|
||
[SerializeField] [Min(1)] private float infoOutTime = 2f;
|
||
[SerializeField] [Min(1)]
|
||
[Tooltip("boss攻击倒计时小于等于这个时间 就显示这个特效")]
|
||
private int bossAttackWarningSeconds = 30;
|
||
|
||
[Header("scene crack effect")]
|
||
[SerializeField]private Vector2 minPositonOffset = Vector2.zero;
|
||
[SerializeField]private Vector2 maxPositonOffset = Vector2.zero;
|
||
#region player
|
||
|
||
[Header("play attack")]
|
||
[SerializeField] [Tooltip("开始从转盘结束开始算,时间结束开始播放boss受击动画")]
|
||
private float bossAttackedDelay1 = 0.5f;
|
||
[SerializeField][Tooltip("开始从转盘结束开始算,时间结束开始播放boss受击动画")]
|
||
private float bossAttackedDelay2 = 0.5f;
|
||
[SerializeField] [Tooltip("开始从转盘结束开始算,时间结束开始播放boss受击动画特效")]
|
||
private float bossAttackedFxDelay1 = 0.5f;
|
||
[SerializeField][Tooltip("开始从转盘结束开始算,时间结束开始播放boss受击动画特效")]
|
||
private float bossAttackedFxDelay2 = 0.5f;
|
||
[SerializeField] [Tooltip("开始从转盘结束开始算,时间结束开始播放boss血条动画")]
|
||
private float bossAttackedHpAniDelay1 = 0.5f;
|
||
[SerializeField][Tooltip("开始从转盘结束开始算,时间结束开始播放boss血条动画")]
|
||
private float bossAttackedHpAniDelay2 = 0.5f;
|
||
[SerializeField] protected float playAttackTier2Interval=0.5f;
|
||
[SerializeField][Min(1)] protected int playAttackTier2Count =1;
|
||
[SerializeField] [Tooltip("血条清空之后,延迟一个时间播boss死亡动画")]
|
||
private float bossDeathDelay = 0.5f;
|
||
[SerializeField][Tooltip("玩家攻击的震动数据,必须有3个")]
|
||
List<EventBossFightShakeData> playerShakeData;
|
||
|
||
[Header("shield")]
|
||
[SerializeField] private float shieldAddTime = 0.5f;
|
||
[SerializeField] [Tooltip("连续播盾牌飞入动画的间隔时间")]
|
||
private float shieldAddIntervalTime = 0.5f;
|
||
[SerializeField] [Tooltip("盾牌飞入动画delay一段时间之后 刷新显示")]
|
||
private float shieldDelayTime1 = 0.5f;
|
||
[SerializeField] [Tooltip("盾牌飞入到破碎位置delay一段时间之后 播碎裂动画")]
|
||
private float shieldDelayTime2= 0.5f;
|
||
[SerializeField] private GameObject shieldGameObject;
|
||
[SerializeField] private float shieldReduceTime;
|
||
[Header("hp")]
|
||
[SerializeField] private float hpAddTime = 0.5f;
|
||
[Header("token")]
|
||
[SerializeField] private float tokenAddTime = 0.5f;
|
||
[SerializeField] private GameObject hurt_fx_position;
|
||
#endregion
|
||
#endregion
|
||
|
||
private bool _isRotating;
|
||
private bool _isOpening=true;
|
||
private bool _isBossDeath;
|
||
private bool _isPlayerDeath;
|
||
private readonly int _showRewardCount = 4;
|
||
private EventBossFightStage _stageConfigWithUI ;
|
||
private EventBossFightRectFollowerGraphic _eventRectFollowerGraphic;
|
||
protected IEventBossFightBossCell _bossCell;
|
||
private List<IWheelReward> _wheelRewards;
|
||
private EventBossFightManager _manager;
|
||
private EventBossFightManager Manager => _manager ??= GContext.container.Resolve<EventBossFightManager>();
|
||
protected EventBossFightData Data => Manager?.Data;
|
||
private GameObject[] _sceneCrackFxs=new GameObject[5];
|
||
private AsyncOperationHandle<GameObject> _bossInstantiateHandle;
|
||
protected virtual void Awake()
|
||
{
|
||
//fx
|
||
fx_eventbossfight_warning=gameObject.FindChildGameObject("fx_eventbossfight_warning");
|
||
fx_eventbossfight_wheel_shieldswitch=gameObject.FindChildGameObject("fx_eventbossfight_wheel_shieldswitch");
|
||
fx_eventbossfight_wheel_healswitch=gameObject.FindChildGameObject("fx_eventbossfight_wheel_healswitch");
|
||
fx_eventbossfight_wheel_heal_01=gameObject.FindChildGameObject("fx_eventbossfight_wheel_heal_01");
|
||
fx_eventbossfight_wheel_heal_02=gameObject.FindChildGameObject("fx_eventbossfight_wheel_heal_02");
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
var obj = gameObject.FindChildGameObject($"fx_eventbossfight_submarine_attacked0{i+1}");
|
||
if (!obj) continue;
|
||
obj.SetActive(false);
|
||
_sceneCrackFxs[i]=obj;
|
||
}
|
||
|
||
_enterDirector=gameObject.FindChildGameObject("root").GetComponent<PlayableDirector>();
|
||
|
||
//top
|
||
_finalReward = gameObject.FindChildGameObject("p_final_reward").GetComponentInChildren<RewardItemNew>();
|
||
_textTime = gameObject.FindChildGameObject("p_text_event_time").GetComponent<TMP_Text>();
|
||
|
||
_bossReward = gameObject.FindChildGameObject("p_boss_reward").GetComponentsInChildren<RewardItemNew>();
|
||
_textBossHp = gameObject.FindChildGameObject("p_text_bossHp").GetComponent<TMP_Text>();
|
||
_imgBossHpBar=gameObject.FindChildGameObject("p_img_boss_hp_bar").GetComponent<Image>();
|
||
_bossRewardFinal=gameObject.FindChildGameObject("p_boss_reward_final").GetComponent<RewardItemNew>();
|
||
_textBossHpFinal = gameObject.FindChildGameObject("p_text_bossHp_final").GetComponent<TMP_Text>();
|
||
_imgBossHpBarFinal=gameObject.FindChildGameObject("p_img_boss_hp_bar_final").GetComponent<Image>();
|
||
_hpBossObj = gameObject.FindChildGameObject("hp_boss");
|
||
_hpBossObjFinal = gameObject.FindChildGameObject("hp_boss_final");
|
||
|
||
_levels = gameObject.FindChildGameObject("level").GetComponentsInChildren<SandDigLevel>();
|
||
_btnQuestionmark = gameObject.FindChildGameObject("p_btn_questionmark").GetComponentInChildren<Button>();
|
||
_btnQuestionmark.onClick.AddListener(OnClickBtnQuestionMark);
|
||
_goBtnFightInfo = gameObject.FindChildGameObject("p_btn_fight_info");
|
||
_btnFightInfo = _goBtnFightInfo.GetComponentInChildren<Button>();
|
||
_btnFightInfo.onClick.AddListener(OnClickBtnBossInfo);
|
||
_textBossAttackTime = gameObject.FindChildGameObject("p_text_boss_attack_time").GetComponent<TMP_Text>();
|
||
_textBossAttackRange = gameObject.FindChildGameObject("p_text_boss_attack_range").GetComponent<TMP_Text>();
|
||
_objTipsBoss = gameObject.FindChildGameObject("p_tips_boss");
|
||
|
||
//center
|
||
var bossGo = gameObject.FindChildGameObject("boss");
|
||
_bossMount = bossGo ? bossGo.transform : null;
|
||
hurt_fx_position = gameObject.FindChildGameObject("hurt_fx_position");
|
||
_playerCell = gameObject.FindChildGameObject("weapon").GetComponent<EventBossFightTimelinePlayerCell>();
|
||
_playerDirector = gameObject.FindChildGameObject("wheel").GetComponent<PlayableDirector>();
|
||
_eventRectFollowerGraphic =
|
||
gameObject.FindChildGameObject("fx_boss_bone_follower")?.GetComponent<EventBossFightRectFollowerGraphic>();
|
||
if (_eventRectFollowerGraphic)
|
||
_eventRectFollowerGraphic.enabled = false;
|
||
else
|
||
Debug.LogWarning(
|
||
"EventBossFightMainPanel:请在 fx_boss_bone_follower 上添加 EventBossFightRectFollowerGraphic。",
|
||
this);
|
||
|
||
//bottom
|
||
_wheel = transform.GetComponentInChildren<EventBossFightWheelRewardComponent>(true);
|
||
_goSpinButtonRoot = gameObject.FindChildGameObject("btn_spin");
|
||
_goMagnificationRoot = gameObject.FindChildGameObject("btn_magnification");
|
||
_btnSpin = _goSpinButtonRoot.GetComponentInChildren<Button>();
|
||
_btnSpin.onClick.AddListener(OnClickBtnSpin);
|
||
_textSpin = _btnSpin.gameObject.FindChildGameObject("p_text_spin").GetComponentInChildren<TMP_Text>();
|
||
_btnMagnification = _goMagnificationRoot.GetComponentInChildren<Button>();
|
||
_btnMagnification.onClick.AddListener(OnClickBtnMagnification);
|
||
_textMagnification = _btnMagnification.gameObject.FindChildGameObject("text_magnification")
|
||
.GetComponent<TMP_Text>();
|
||
_objMagnification = _btnMagnification.gameObject.FindChildGameObject("magnification_max");
|
||
_btnAdd = gameObject.FindChildGameObject("btn_add").GetComponentInChildren<Button>();
|
||
_btnAdd.onClick.AddListener(OnClickBtnAdd);
|
||
_btnClose = gameObject.FindChildGameObject("p_btn_close").GetComponent<Button>();
|
||
_btnClose.onClick.AddListener(OnClickBtnClose);
|
||
_textPlayerHp = gameObject.FindChildGameObject("p_text_player_hp").GetComponent<TMP_Text>();
|
||
_textPlayerChangeHp=gameObject.FindChildGameObject("p_text_player_hp_deduct").GetComponent<TMP_Text>();
|
||
_imgPlayerHpBar=gameObject.FindChildGameObject("p_img_player_hp_bar").GetComponent<Image>();
|
||
_shields = gameObject.FindChildGameObject("p_shields").GetComponentsInChildren<Image>();
|
||
_shieldBtns=gameObject.FindChildGameObject("p_shields").GetComponentsInChildren<Button>();
|
||
foreach (var shieldBtn in _shieldBtns)
|
||
{
|
||
shieldBtn.onClick.AddListener(OnClickBtnShield);
|
||
}
|
||
_textTokenAmount = gameObject.FindChildGameObject("p_text_token_amount").GetComponent<TMP_Text>();
|
||
_imgTokenIcon = gameObject.FindChildGameObject("p_img_token_icon").GetComponent<Image>();
|
||
_iconHpTarget=gameObject.FindChildGameObject("p_icon_hp_target").GetComponent<RectTransform>();
|
||
_iconHpBtn = _iconHpTarget.GetComponent<Button>();
|
||
_iconHpBtn.onClick.AddListener(OnClickBtnHpIcon);
|
||
_tipsHp=gameObject.FindChildGameObject("p_tips_hp");
|
||
_tipsHpBtnClose=gameObject.FindChildGameObject("p_tips_hp_btn_close").GetComponent<Button>();
|
||
_tipsHpBtnClose.onClick.AddListener(OnClickBtnHpIconClose);
|
||
_tipsShield=gameObject.FindChildGameObject("p_tips_sheild");
|
||
_tipsShieldBtnClose=gameObject.FindChildGameObject("p_tips_sheild_btn_close").GetComponent<Button>();
|
||
_tipsShieldBtnClose.onClick.AddListener(OnClickBtnShieldIconClose);
|
||
_shieldAddAni=gameObject.FindChildGameObject("shield_add").GetComponent<Animation>();
|
||
_hpAddAni=gameObject.FindChildGameObject("hp_add").GetComponent<Animation>();
|
||
_tokenShieldGameObject=gameObject.FindChildGameObject("token_add_shield");
|
||
_tokenHpGameObject=gameObject.FindChildGameObject("token_add_hp");
|
||
RewardFlyBatchCtrl = gameObject.FindChildGameObject(nameof(RewardFlyBatchCtrl))
|
||
.GetComponent<RewardFlyBatchController>();
|
||
_goPaidReviveRoot = gameObject.FindChildGameObject("btn_revive");
|
||
if (_goPaidReviveRoot)
|
||
{
|
||
_btnPaidRevive = _goPaidReviveRoot.GetComponentInChildren<Button>(true);
|
||
_textPaidRevivePrice = _goPaidReviveRoot.GetComponentInChildren<TMP_Text>(true);
|
||
if (_btnPaidRevive)
|
||
_btnPaidRevive.onClick.AddListener(OnClickBtnPaidRevive);
|
||
_goPaidReviveRoot.SetActive(false);
|
||
}
|
||
|
||
GContext.OnEvent<RewardPanelClose>().Subscribe(OnRewardPanelClose).AddTo(disposables);
|
||
}
|
||
|
||
|
||
protected override void Start()
|
||
{
|
||
base.Start();
|
||
OnStart();
|
||
GContext.container.Resolve<GuideDataCenter>().InspectTriggerGuide("EventBossFightUnderseaPanel",curPanelName:gameObject.name);
|
||
Observable.Interval(TimeSpan.FromSeconds(1f)).Subscribe(UpdateTimer).AddTo(disposables);
|
||
}
|
||
|
||
public void OnStart()
|
||
{
|
||
_ = OnStartAsync();
|
||
}
|
||
|
||
private async Task OnStartAsync()
|
||
{
|
||
try
|
||
{
|
||
if (!ValidateBossStageForStart())
|
||
return;
|
||
_bossInstantiateHandle = await EventBossFightPerStageVideoBossLoader.LoadAddressableBossIfNeededAsync(
|
||
_bossMount, Data.InitConfig, Data.StageCountFrom1, _bossInstantiateHandle);
|
||
InitData();
|
||
_ = UpdateBossAttackTime(false, true);
|
||
InitUI();
|
||
ShowUI();
|
||
ShowBossSpine();
|
||
if (Data.IsShowTips)
|
||
{
|
||
OnClickBtnBossInfo();
|
||
Manager.SetShowTipsState(false);
|
||
}
|
||
ShowProgressReward();
|
||
UpdateTimer(0);
|
||
PlayEnterDirectorAndHandoffToBossIdle();
|
||
PrefetchNextBossBundleIfNeeded();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
private bool ValidateBossStageForStart()
|
||
{
|
||
if (Data == null || Data.InitConfig == null)
|
||
return false;
|
||
if (string.IsNullOrEmpty(Data.InitConfig.AssetBundle))
|
||
{
|
||
Debug.LogError("EventBossFight:InitConfig.AssetBundle 未配置,Boss 视频分包必填。");
|
||
return false;
|
||
}
|
||
|
||
var resolvedCount = Manager.GetResolvedStageIds().Count;
|
||
if (Data.StageCountFrom1 < 1 || Data.StageCountFrom1 > resolvedCount)
|
||
{
|
||
Debug.LogError($"Boss 关卡索引非法 StageCountFrom1={Data.StageCountFrom1}");
|
||
return false;
|
||
}
|
||
|
||
if (!_bossMount)
|
||
{
|
||
Debug.LogError("EventBossFight:未找到 boss 挂载节点。");
|
||
return false;
|
||
}
|
||
|
||
if (!EventBossFightPerStageVideoBossLoader.IsBundledBossReadyForStage(Data.InitConfig,
|
||
Data.StageCountFrom1))
|
||
{
|
||
Debug.LogError("EventBossFight:无法解析本关 Boss Addressables 键。");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
private void PrefetchNextBossBundleIfNeeded()
|
||
{
|
||
if (Data?.InitConfig == null)
|
||
return;
|
||
if (Data.IsLastStage)
|
||
return;
|
||
var nextKey = EventBossFightBossBundleKeys.GetAddressableKey(Data.InitConfig, Data.StageCountFrom1 + 1);
|
||
if (string.IsNullOrEmpty(nextKey))
|
||
return;
|
||
var loadResourceService = GContext.container.Resolve<ILoadResourceService>();
|
||
// 与 InstantiateAsync / CheckResourceLoadQueue 传入的字符串必须一致:Addressables 按「地址或 Label」解析,
|
||
// 由组配置决定该 key 是资产 Address、是 Label 还是与 prefab 名相同;只要与可寻址条目一致即可下载依赖 Bundle。
|
||
loadResourceService.EnqueueBundleSilently(new List<string> { nextKey });
|
||
}
|
||
|
||
/// <summary>
|
||
/// 面板 enter Timeline 与当前关 Boss Cell 的 show→idle 并行;Boss show 结束与切 idle 由 Cell 自行驱动。
|
||
/// </summary>
|
||
private void PlayEnterDirectorAndHandoffToBossIdle()
|
||
{
|
||
_isOpening = true;
|
||
if (_enterDirector)
|
||
{
|
||
_enterDirector.stopped -= OnEnterDirectorRootStopped;
|
||
_enterDirector.stopped += OnEnterDirectorRootStopped;
|
||
_enterDirector.Play();
|
||
}
|
||
|
||
RunBossShowThenIdleAsync();
|
||
}
|
||
|
||
private void OnEnterDirectorRootStopped(PlayableDirector d)
|
||
{
|
||
if (d)
|
||
d.stopped -= OnEnterDirectorRootStopped;
|
||
}
|
||
|
||
private async void RunBossShowThenIdleAsync()
|
||
{
|
||
try
|
||
{
|
||
if (_bossCell is EventBossFightTimelineBossCellVideo vb)
|
||
await vb.PlayShowThenIdleAsync();
|
||
else if (_bossCell != null)
|
||
{
|
||
_bossCell.ShowGameObject();
|
||
_bossCell.PlayIdle(_bossCell.BossTimelineDirector);
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogException(e);
|
||
}
|
||
finally
|
||
{
|
||
_isOpening = false;
|
||
}
|
||
}
|
||
|
||
private void InitData()
|
||
{
|
||
//ui 显示数据
|
||
CheckStageState();
|
||
_isOpening = true;
|
||
_isBossDeath = false;
|
||
_isPlayerDeath = false;
|
||
_stageConfigWithUI = Data.StageConfig;
|
||
}
|
||
|
||
private void InitBossSpine()
|
||
{
|
||
if (!_bossMount)
|
||
return;
|
||
for (var i = 0; i < _bossMount.childCount; i++)
|
||
_bossMount.GetChild(i).gameObject.SetActive(false);
|
||
var canvasGroup = _bossMount.GetComponent<CanvasGroup>();
|
||
if (!canvasGroup)
|
||
return;
|
||
canvasGroup.alpha = 1;
|
||
}
|
||
private void ShowBossSpine()
|
||
{
|
||
Transform stageChild = null;
|
||
if (EventBossFightPerStageVideoBossLoader.TryGetBossRootFromHandle(_bossInstantiateHandle, out var fromHandle))
|
||
stageChild = fromHandle;
|
||
else if (EventBossFightPerStageVideoBossLoader.TryFindEmbeddedBossSlotRoot(_bossMount, Data.InitConfig,
|
||
Data.StageCountFrom1, out var embedded))
|
||
stageChild = embedded;
|
||
|
||
if (stageChild == null)
|
||
{
|
||
Debug.LogError(
|
||
$"[EventBossFightMainPanel] 当前关 Boss 未就绪(无 Addressables 实例且 boss 下无嵌入式槽位),StageCountFrom1={Data.StageCountFrom1},期望子物体名:{EventBossFightBossBundleKeys.GetAddressableKey(Data.InitConfig, Data.StageCountFrom1)}",
|
||
_bossMount);
|
||
return;
|
||
}
|
||
|
||
// InitBossSpine 会关掉 boss 下所有子物体;须先激活本关槽位根,否则 Cell.SetActive 无法显示
|
||
stageChild.gameObject.SetActive(true);
|
||
|
||
_bossCell = EventBossFightPerStageVideoBossLoader.ResolveVideoBossCell(stageChild);
|
||
if (_bossCell == null)
|
||
{
|
||
Debug.LogError(
|
||
$"Boss 上未找到 EventBossFightTimelineBossCellVideo,StageCountFrom1={Data.StageCountFrom1}",
|
||
stageChild);
|
||
return;
|
||
}
|
||
_bossCell.ShowGameObject();
|
||
OnBossCellBound(_bossCell);
|
||
ResetVideoBossCellDirectorState();
|
||
}
|
||
|
||
private void ResetVideoBossCellDirectorState()
|
||
{
|
||
if (_bossCell is not EventBossFightTimelineBossCellVideo vb)
|
||
return;
|
||
var cd = vb.CellPlayableDirector;
|
||
if (!cd)
|
||
return;
|
||
// 勿在 playableAsset==null 时 Play():图可能未建立,后续 WaitDirectorSegmentFinished 会误判已结束,入场 show 被跳过。
|
||
cd.Stop();
|
||
cd.time = 0;
|
||
cd.extrapolationMode = DirectorWrapMode.None;
|
||
cd.playableAsset = null;
|
||
}
|
||
|
||
private void OnBossCellBound(IEventBossFightBossCell cell)
|
||
{
|
||
if (cell is not EventBossFightTimelineBossCellVideo videoBoss)
|
||
return;
|
||
videoBoss.InitFlash();
|
||
BindBossHurtAnchorsFromHurtFxPosition(videoBoss);
|
||
if (!_eventRectFollowerGraphic)
|
||
return;
|
||
if (videoBoss.bossFollowAnchor)
|
||
_eventRectFollowerGraphic.SetTarget(videoBoss.bossFollowAnchor);
|
||
_eventRectFollowerGraphic.enabled = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 受击飘字/特效挂点:收集 <see cref="hurt_fx_position"/> 下<strong>全部</strong>带 RectTransform 的直接子节点(顺序同 Hierarchy),写入分包 Cell。
|
||
/// </summary>
|
||
private void BindBossHurtAnchorsFromHurtFxPosition(EventBossFightTimelineBossCellVideo videoBoss)
|
||
{
|
||
if (!hurt_fx_position || !videoBoss)
|
||
return;
|
||
var parent = hurt_fx_position.transform;
|
||
var ordered = new List<RectTransform>();
|
||
for (var c = 0; c < parent.childCount; c++)
|
||
{
|
||
var ch = parent.GetChild(c);
|
||
if (ch.TryGetComponent<RectTransform>(out var rt))
|
||
ordered.Add(rt);
|
||
}
|
||
|
||
if (ordered.Count == 0)
|
||
{
|
||
Debug.LogWarning(
|
||
"EventBossFightMainPanel:hurt_fx_position 下没有带 RectTransform 的直接子节点,受击挂点将回退 bossFollowAnchor。",
|
||
hurt_fx_position);
|
||
return;
|
||
}
|
||
|
||
videoBoss.bossHurtAnchors = ordered.ToArray();
|
||
}
|
||
|
||
/// <summary>受击随机挂点下标:与 <see cref="EventBossFightTimelineBossCellVideo.bossHurtAnchors"/> 数量一致;无挂点则返回 0(由 GetHurtAnchor 回退跟随点)。</summary>
|
||
private static int PickRandomBossHurtAnchorIndex(EventBossFightTimelineBossCellVideo vb)
|
||
{
|
||
var n = vb != null && vb.bossHurtAnchors != null ? vb.bossHurtAnchors.Length : 0;
|
||
return n > 0 ? Random.Range(0, n) : 0;
|
||
}
|
||
|
||
private void CheckStageState()
|
||
{
|
||
Manager.CheckStageBossStateNoRewardPanel();
|
||
Manager.CheckStageIsMax();
|
||
Manager.CheckPlayIsDead();
|
||
if (Data.IsShowGuide)
|
||
{
|
||
Manager.SetGuideState(false);
|
||
return;
|
||
}
|
||
if (Data.IsRest)
|
||
Manager.ShowReviewPanel();
|
||
Manager.ApplyPendingFightBootstrapIfNeeded();
|
||
}
|
||
|
||
protected override void OnDestroy()
|
||
{
|
||
EventBossFightPerStageVideoBossLoader.ReleaseAddressableBoss(ref _bossInstantiateHandle);
|
||
if (_enterDirector)
|
||
_enterDirector.stopped -= OnEnterDirectorRootStopped;
|
||
_sceneCrackFxs = null;
|
||
_wheelRewards?.Clear();
|
||
_wheelRewards = null;
|
||
_btnAdd.onClick.RemoveAllListeners();
|
||
if (_btnPaidRevive)
|
||
_btnPaidRevive.onClick.RemoveListener(OnClickBtnPaidRevive);
|
||
_btnSpin.onClick.RemoveAllListeners();
|
||
_btnFightInfo.onClick.RemoveAllListeners();
|
||
_btnQuestionmark.onClick.RemoveAllListeners();
|
||
_btnMagnification.onClick.RemoveAllListeners();
|
||
_btnClose.onClick.RemoveAllListeners();
|
||
_iconHpBtn.onClick.RemoveAllListeners();
|
||
_tipsHpBtnClose.onClick.RemoveAllListeners();
|
||
_tipsShieldBtnClose.onClick.RemoveAllListeners();
|
||
foreach (var shieldBtn in _shieldBtns)
|
||
{
|
||
shieldBtn.onClick.RemoveAllListeners();
|
||
}
|
||
UIManager.Instance?.UI3DCamera?.gameObject?.SetActive(false);
|
||
base.OnDestroy();
|
||
}
|
||
|
||
private void InitUI()
|
||
{
|
||
_textTime.text = string.Empty;
|
||
_textSpin.text = string.Empty;
|
||
_textBossAttackRange.text = string.Empty;
|
||
_textBossAttackTime.text = string.Empty;
|
||
_textBossHp.text = string.Empty;
|
||
_textBossHpFinal.text = string.Empty;
|
||
_textMagnification.text = string.Empty;
|
||
_textPlayerHp.text = string.Empty;
|
||
_objMagnification.SetActive(false);
|
||
_objTipsBoss.SetActive(false);
|
||
_imgBossHpBar.fillAmount = 1;
|
||
_imgBossHpBarFinal.fillAmount = 1;
|
||
_imgPlayerHpBar.fillAmount = 1;
|
||
for (int i = 0; i < _shields.Length; i++)
|
||
{
|
||
_shields[i].gameObject.SetActive(false);
|
||
}
|
||
InitBossSpine();
|
||
}
|
||
private TimeSpan _nextAttackTime;
|
||
private void UpdateTimer(long obj)
|
||
{
|
||
if (Data == null)
|
||
return;
|
||
|
||
_textTime.text = ConvertTools.ConvertTime2(Data.RemainingTime);
|
||
_= UpdateBossAttackTime();
|
||
}
|
||
|
||
private async Task UpdateBossAttackTime(bool isShowAttackEffect=true,bool isRemainOnce=false)
|
||
{
|
||
if (Manager.IsAwaitingPaidRevive())
|
||
return;
|
||
|
||
if (Data.HasPendingLastAttack&&isShowAttackEffect)
|
||
{
|
||
if(_isOpening) return;
|
||
if (Manager.ExecutePendingLastAttack(out var isReduceShield, out var isReducePlayerHp, out int damage))
|
||
{
|
||
_textPlayerChangeHp.text = $"-{damage}";
|
||
await PlayBossAttackEffect(isReduceShield, isReducePlayerHp);
|
||
} //todo 表现和数据没分开 ,表现影响了数据的处理
|
||
return;
|
||
}
|
||
|
||
if(_isBossDeath||_isPlayerDeath)
|
||
return;
|
||
if (Data.IsRest&&!_isBossDeath)
|
||
_nextAttackTime = TimeSpan.FromSeconds(_stageConfigWithUI.AttackInterval) ;
|
||
else
|
||
_nextAttackTime=DateTimeOffset.FromUnixTimeSeconds(Data.BossAttackTime).DateTime-ZZTimeHelper.UtcNow();
|
||
fx_eventbossfight_warning.gameObject.SetActive(_nextAttackTime.TotalSeconds <= bossAttackWarningSeconds);
|
||
if (_nextAttackTime.TotalSeconds <= 0&&!_isRotating)
|
||
{
|
||
if (isShowAttackEffect&&_isOpening)return;
|
||
|
||
if (Manager.TryBossAttack(out var isReduceShield,out var isReducePlayerHp,isRemainOnce,out int damage))
|
||
{
|
||
if (isShowAttackEffect)
|
||
{
|
||
_textPlayerChangeHp.text = $"-{damage}";
|
||
await PlayBossAttackEffect(isReduceShield,isReducePlayerHp);
|
||
//Manager.TryTriggerGuidance();
|
||
}
|
||
}
|
||
}
|
||
|
||
var time = _nextAttackTime > TimeSpan.Zero ? _nextAttackTime : TimeSpan.Zero;
|
||
_textBossAttackTime.text = ConvertTools.ConvertTime2(time);
|
||
}
|
||
|
||
private void ShowUI()
|
||
{
|
||
if (Data == null) return;
|
||
ShowMagnificationInfo();
|
||
ShowLevelInfo();
|
||
ShowWheelReward();
|
||
ShowTokenAmount();
|
||
ShowPlayerHp();
|
||
ShowPlayerShield();
|
||
ShowBossHp();
|
||
ShowTokenImage();
|
||
|
||
var attackRange = Manager.GetBossAttackRange(_stageConfigWithUI);
|
||
_textBossAttackRange.text=$"{attackRange.minDamage}~{attackRange.maxDamage} ";
|
||
|
||
SetButtonState(true);
|
||
_finalReward.InflationRate = Data.InflationRate;
|
||
_finalReward.SetDropIcon("", Manager.GetFinalBossRewardsDropID());
|
||
_bossRewardFinal.InflationRate = Data.InflationRate;
|
||
_bossRewardFinal.SetDropIcon("", Manager.GetFinalBossRewardsDropID());
|
||
_hpBossObj.SetActive(!Data.IsLastStage);
|
||
_hpBossObjFinal.SetActive(Data.IsLastStage);
|
||
ApplyPaidReviveAndSpinLayout();
|
||
}
|
||
|
||
private void ShowProgressReward()
|
||
{
|
||
var progressRewards = Manager.GetBossRewards();
|
||
if (progressRewards is not { Count: > 0 }) return;
|
||
for (var i = 0; i < progressRewards.Count; i++)
|
||
{
|
||
if(i>=_bossReward.Length) break;
|
||
_bossReward[i].SetData(progressRewards[i]);
|
||
_bossReward[i].gameObject.SetActive(true);
|
||
}
|
||
}
|
||
|
||
private void ShowTokenImage()
|
||
{
|
||
var itemImgName = Manager.GetTokenName();
|
||
if(!string.IsNullOrEmpty(itemImgName))
|
||
_ = GContext.container.Resolve<IUIService>().SetImageSprite(_imgTokenIcon, itemImgName);
|
||
}
|
||
|
||
private void ShowPlayerShield(bool isShowAddEffect=false)
|
||
{
|
||
for (int i = 0; i < _shields.Length; i++)
|
||
{
|
||
var shield = _shields[i];
|
||
var isActive=shield.isActiveAndEnabled;
|
||
shield.gameObject.SetActive(i < Data.PlayerShowShield);
|
||
var fx=shield.gameObject.FindChildGameObject("fx_eventbossfight_wheel_shield");
|
||
if(!fx.activeInHierarchy)
|
||
fx.SetActive(!isActive && shield.isActiveAndEnabled && isShowAddEffect);
|
||
}
|
||
}
|
||
private int currentPlayerShowHp=0;
|
||
private void ShowPlayerHp()
|
||
{
|
||
currentPlayerShowHp=Data.PlayerShowHp;
|
||
_textPlayerHp.text=$"{Data.PlayerShowHp}";
|
||
_imgPlayerHpBar.fillAmount = (float)Data.PlayerShowHp / _stageConfigWithUI.PlayerHP;
|
||
UpdateFightInfoVisibility();
|
||
}
|
||
|
||
/// <summary>玩家阵亡时隐藏 Boss 出手说明与倒计时;存活或治疗后恢复。</summary>
|
||
private void UpdateFightInfoVisibility()
|
||
{
|
||
var alive = Data != null && Data.PlayerRemainHp > 0;
|
||
if (_goBtnFightInfo)
|
||
_goBtnFightInfo.SetActive(alive);
|
||
if (!alive && _objTipsBoss)
|
||
_objTipsBoss.SetActive(false);
|
||
}
|
||
private void PlayPlayerHpTextAni()
|
||
{
|
||
DOTween.To(() => currentPlayerShowHp, x => currentPlayerShowHp = x, Data.PlayerShowHp, hpTextChangeTime).OnUpdate(() =>
|
||
{
|
||
_textPlayerHp.text =$"{currentPlayerShowHp}";
|
||
}).SetId(nameof(_textPlayerHp));
|
||
}
|
||
private void ShowBossHp()
|
||
{
|
||
_textBossHp.text=$"{Data.BossRemainHp}";
|
||
_textBossHpFinal.text=$"{Data.BossRemainHp}";
|
||
_imgBossHpBar.fillAmount=(float)Data.BossRemainHp/_stageConfigWithUI.BossHP;
|
||
_imgBossHpBarFinal.fillAmount=(float)Data.BossRemainHp/_stageConfigWithUI.BossHP;
|
||
}
|
||
|
||
private void ShowTokenAmount()
|
||
{
|
||
_textTokenAmount.text=$"{Manager.GetTokenCount()}";
|
||
}
|
||
|
||
private void ShowWheelReward()
|
||
{
|
||
_wheelRewards = Manager.GetWheelRewards();
|
||
if (_wheelRewards == null || _wheelRewards.Count == 0) return ;
|
||
|
||
_wheel.SetData(_wheelRewards);
|
||
_wheel.ShowUI();
|
||
}
|
||
|
||
private void ShowMagnificationInfo()
|
||
{
|
||
_textMagnification.text = $"X{Data.Magnification}";
|
||
_textSpin.text=$"X{Data.Magnification*Data.InitConfig.SpinRequire}";
|
||
var spinMag = Data.InitConfig.SpinMag;
|
||
_objMagnification.SetActive(spinMag != null && spinMag.Count > 0 &&
|
||
spinMag[spinMag.Count - 1] == Data.Magnification);
|
||
}
|
||
|
||
private void ShowLevelInfo()
|
||
{
|
||
if (Data == null) return;
|
||
|
||
var stageCount = Manager.GetResolvedStageIds().Count;
|
||
if (stageCount <= 0) return;
|
||
var curIndex = (Data.StageCountFrom1-1) % stageCount;
|
||
|
||
int startIndex= curIndex - 1;
|
||
var offsetIndex = stageCount - _showRewardCount;
|
||
if (curIndex <= 1)
|
||
startIndex = 0;
|
||
else if (curIndex > offsetIndex)
|
||
startIndex = offsetIndex;
|
||
|
||
for (int i = 0; i < _showRewardCount; i++)
|
||
{
|
||
int index = startIndex + i;
|
||
if (index >= stageCount)
|
||
break;
|
||
int state = 0;
|
||
if (index < curIndex)
|
||
state = 2;
|
||
else if (index == curIndex)
|
||
state = 1;
|
||
_levels[i].SetState(state);
|
||
_levels[i].SetTextNum($"{index + 1}");
|
||
}
|
||
_levels[_showRewardCount - 1].SetTextNum($"{stageCount}");
|
||
}
|
||
|
||
#region Button
|
||
private void OnClickBtnQuestionMark()
|
||
{
|
||
if (Data?.InitConfig == null) return;
|
||
UITypes.EventBossFightInfoPanel.SetType(Data.InitConfig.InfoPanel);
|
||
_ = UIManager.Instance.ShowUILoad(UITypes.EventBossFightInfoPanel);
|
||
}
|
||
private void OnClickBtnMagnification()
|
||
{
|
||
if (Manager.IsAwaitingPaidRevive())
|
||
return;
|
||
var index = Data.InitConfig.SpinMag.FindIndex(x => x == Data.Magnification);
|
||
var targetIndex=index+1;
|
||
if(targetIndex>=Data.InitConfig.SpinMag.Count)
|
||
targetIndex=0;
|
||
Data.Magnification = Data.InitConfig.SpinMag[targetIndex];
|
||
ShowMagnificationInfo();
|
||
ShowWheelReward();
|
||
}
|
||
|
||
private void OnClickBtnClose()
|
||
{
|
||
try
|
||
{
|
||
EventBossFightActTransition.PublishSwitchToFishing(Data?.InitConfig);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
/// <summary>阵亡弹窗点确认关闭后回到主界面时刷新:显示复活入口、隐藏转盘与倍率。</summary>
|
||
public void OnReturnFromEndingPopupToMain()
|
||
{
|
||
ApplyPaidReviveAndSpinLayout();
|
||
ShowPlayerHp();
|
||
}
|
||
|
||
void ApplyPaidReviveAndSpinLayout()
|
||
{
|
||
if (Manager == null || Data == null)
|
||
return;
|
||
var awaiting = Manager.IsAwaitingPaidRevive();
|
||
if (_goSpinButtonRoot)
|
||
_goSpinButtonRoot.SetActive(!awaiting);
|
||
if (_goMagnificationRoot)
|
||
_goMagnificationRoot.SetActive(!awaiting);
|
||
if (_goPaidReviveRoot)
|
||
{
|
||
_goPaidReviveRoot.SetActive(awaiting);
|
||
if (awaiting && _textPaidRevivePrice)
|
||
{
|
||
var iapId = Manager.GetPaidReviveIapTableId();
|
||
GContext.container.Resolve<PlayerItemData>().ResolveIapId(iapId, out _, out var price);
|
||
_textPaidRevivePrice.text =
|
||
LocalizationMgr.GetFormatTextValue("UI_Event1v1BattleSlapPanel_15", price);
|
||
}
|
||
}
|
||
}
|
||
|
||
private async void OnClickBtnPaidRevive()
|
||
{
|
||
try
|
||
{
|
||
if (!Manager.IsAwaitingPaidRevive())
|
||
return;
|
||
if (!await Manager.TryPurchasePaidReviveAsync())
|
||
return;
|
||
OnPaidReviveSuccess();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
/// <summary>付费复活成功后清除死亡表现并恢复转盘区域显示。</summary>
|
||
public void OnPaidReviveSuccess()
|
||
{
|
||
_isPlayerDeath = false;
|
||
ShowUI();
|
||
}
|
||
private void OnClickBtnAdd()
|
||
{
|
||
Manager.ShowFestPack();
|
||
}
|
||
private void OnClickBtnHpIcon()
|
||
{
|
||
_tipsHp.SetActive(true);
|
||
}
|
||
private void OnClickBtnHpIconClose()
|
||
{
|
||
_tipsHp.SetActive(false);
|
||
}
|
||
private void OnClickBtnShield()
|
||
{
|
||
_tipsShield.SetActive(true);
|
||
}
|
||
private void OnClickBtnShieldIconClose()
|
||
{
|
||
_tipsShield.SetActive(false);
|
||
}
|
||
private void OnClickBtnBossInfo()
|
||
{
|
||
_objTipsBoss.SetActive(!_objTipsBoss.activeInHierarchy);
|
||
Task.Run(async () =>
|
||
{
|
||
await Awaiters.Seconds(infoOutTime);
|
||
_objTipsBoss?.SetActive(false);
|
||
});
|
||
}
|
||
private void OnClickBtnSpin()
|
||
{
|
||
if (_isRotating) return;
|
||
if (Manager.IsAwaitingPaidRevive())
|
||
return;
|
||
if(!Manager.TryUseToken()) return;
|
||
ShowTokenAmount();
|
||
_isRotating = true;
|
||
SetButtonState(false);
|
||
var index =Manager.GetRandomRewardIndex();
|
||
var reward=_wheelRewards[index];
|
||
Manager.UseDropItem(reward.Index,Data.Magnification,out var convertTokenCount,out var amount);
|
||
|
||
var spinType = Manager.GetSpinType(reward.Index);
|
||
Manager.Agg_event_bossfight(Data.StageCountFrom1,
|
||
Data.RoundCountFrom1,Data.Magnification, spinType, Data.PlayerShieldCount,
|
||
Data.PlayerRemainHp, convertTokenCount,Data.BossRemainHp, Data.BossFightStageGroupIndex + 1);
|
||
_ = _wheel.PlayEffect(index, reward, ()=>WheelEffectCallBack(reward.Index,amount,convertTokenCount));
|
||
}
|
||
|
||
private async void WheelEffectCallBack(int spinPointID,int addAmount,int convertTokenCount)
|
||
{
|
||
try
|
||
{
|
||
await ShowDropItemEffect(spinPointID, addAmount, convertTokenCount);
|
||
_isRotating = false;
|
||
Manager.CheckStageBossState();
|
||
UpdateFightInfoVisibility();
|
||
await UpdateBossAttackTime();
|
||
SetButtonState(true);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
private void SetButtonState(bool isEnable)
|
||
{
|
||
if(_btnAdd)
|
||
_btnAdd.enabled = isEnable;
|
||
if(_btnQuestionmark)
|
||
_btnQuestionmark.enabled = isEnable;
|
||
if (_btnPaidRevive && Manager.IsAwaitingPaidRevive())
|
||
_btnPaidRevive.enabled = isEnable;
|
||
if(_btnSpin && _goSpinButtonRoot && _goSpinButtonRoot.activeInHierarchy)
|
||
_btnSpin.enabled=isEnable;
|
||
if(_btnClose)
|
||
_btnClose.enabled = isEnable;
|
||
if (_btnMagnification && _goMagnificationRoot && _goMagnificationRoot.activeInHierarchy)
|
||
_btnMagnification.enabled = isEnable;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region playerEffect
|
||
private async Task ShowDropItemEffect(int spinPointID,int addAmount,int convertTokenCount)
|
||
{
|
||
var spinPointConfig =Manager.Tables.TbEventBossFightSpinPoints.GetOrDefault(spinPointID);
|
||
switch (spinPointConfig.SpinType)
|
||
{
|
||
case nameof(EEventBossFightSpinType.Cure):
|
||
await PlayRevertHp(convertTokenCount,addAmount);
|
||
break;
|
||
case nameof(EEventBossFightSpinType.Shield):
|
||
await PlayerAddShield(convertTokenCount,addAmount);
|
||
break;
|
||
case nameof(EEventBossFightSpinType.AttackTier1):
|
||
await PlayAttackTier1();
|
||
break;
|
||
case nameof(EEventBossFightSpinType.AttackTier2):
|
||
await PlayAttackTier2();
|
||
break;
|
||
}
|
||
}
|
||
private async Task PlayRevertHp(int convertTokenCount,int addAmount)
|
||
{
|
||
fx_eventbossfight_wheel_heal_01.SetActive(false);
|
||
fx_eventbossfight_wheel_heal_02.SetActive(false);
|
||
fx_eventbossfight_wheel_healswitch.SetActive(false);
|
||
_hpAddAni.gameObject.SetActive(true);
|
||
_hpAddAni.GetComponentInChildren<TMP_Text>().text = $"x{addAmount}";
|
||
_hpAddAni.Play();
|
||
var currentFillAmount = _imgPlayerHpBar.fillAmount;
|
||
await Awaiters.Seconds(hpAddTime);
|
||
await PlayHpAddFly(addAmount);
|
||
fx_eventbossfight_wheel_heal_01.SetActive(true);
|
||
fx_eventbossfight_wheel_heal_02.SetActive(!Mathf.Approximately(currentFillAmount, 1));
|
||
await PlayPlayerHpChangeAni();
|
||
if (convertTokenCount > 0)
|
||
{
|
||
var source = (RectTransform)_tokenHpGameObject.FindChildGameObject("icon").transform;
|
||
var sourceText = (RectTransform)_tokenHpGameObject.FindChildGameObject("text").transform;
|
||
fx_eventbossfight_wheel_healswitch.SetActive(true);
|
||
await PlayTokenAddFly(convertTokenCount,source,sourceText);
|
||
}
|
||
}
|
||
private async Task PlayReduceHp()
|
||
{
|
||
await PlayPlayerHpChangeAni();
|
||
}
|
||
private async Task PlayPlayerHpChangeAni()
|
||
{
|
||
PlayPlayerHpTextAni();
|
||
var fillAmount = (float)Data.PlayerShowHp / _stageConfigWithUI.PlayerHP;
|
||
await _imgPlayerHpBar.DOFillAmount(fillAmount, sliderChangeTime).AsyncWaitForCompletion();
|
||
}
|
||
private async Task PlayHpAddFly(int addAmount)
|
||
{
|
||
var targetRect = GetHpRewardFlyTarget();
|
||
var request = new BatchedRewardFlyRequest
|
||
{
|
||
Icon = new BatchedRewardFlyRequestIcon{icon=_hpAddAni.GetComponentInChildren<Image>().sprite},
|
||
//Quantity = addAmount,
|
||
StartPoint = new BatchedRewardFlyStartPoint(GetHpRewardFlySource()),
|
||
EndPoint = new BatchedRewardFlyEndPoint(targetRect),
|
||
IsDestinationRewardStash = true,
|
||
AnimationParamIndex = 0
|
||
};
|
||
await RewardFlyBatchCtrl.OnRewardFlyRequestAsync(request);
|
||
}
|
||
private RectTransform GetHpRewardFlySource()
|
||
{
|
||
return _hpAddAni.GetComponentInChildren<Image>().rectTransform;
|
||
}
|
||
private RectTransform GetHpRewardFlyTarget()
|
||
{
|
||
return _iconHpTarget;
|
||
}
|
||
private async Task PlayerAddShield(int convertTokenCount,int addAmount)
|
||
{
|
||
fx_eventbossfight_wheel_shieldswitch.gameObject.SetActive(false);
|
||
_shieldAddAni.gameObject.SetActive(true);
|
||
_shieldAddAni.GetComponentInChildren<TMP_Text>().text = $"x{addAmount}";
|
||
_shieldAddAni.Play();
|
||
await Awaiters.Seconds(shieldAddTime);
|
||
var targets= GetShieldRewardFlyTarget(addAmount);
|
||
var remain = addAmount - targets.Count;
|
||
int animationParamIndex = 0;
|
||
foreach (var target in targets)
|
||
{
|
||
await Awaiters.Seconds(shieldAddIntervalTime);
|
||
_= PlayShieldAddFly(1,target,()=>target?.gameObject.SetActive(true),shieldDelayTime1,animationParamIndex);
|
||
animationParamIndex = 1;
|
||
}
|
||
if (convertTokenCount <= 0)
|
||
return;
|
||
// PlayShieldAddSwitchFly(addAmount);
|
||
await Awaiters.Seconds(shieldAddIntervalTime);
|
||
var fxRect=(RectTransform)fx_eventbossfight_wheel_shieldswitch.transform;
|
||
await PlayShieldAddFly(remain,fxRect,()=>
|
||
fx_eventbossfight_wheel_shieldswitch.gameObject.SetActive(true),shieldDelayTime2,animationParamIndex);
|
||
var source = (RectTransform)_tokenShieldGameObject.FindChildGameObject("icon").transform;
|
||
var sourceText = (RectTransform)_tokenShieldGameObject.FindChildGameObject("text").transform;
|
||
await PlayTokenAddFly(remain,source,sourceText);
|
||
}
|
||
|
||
private async Task PlayShieldAddFly(int addAmount,RectTransform target,Action callback,float delayTime,int animationParamIndex)
|
||
{
|
||
var request = new BatchedRewardFlyRequest
|
||
{
|
||
Icon = new BatchedRewardFlyRequestIcon{icon=_shieldAddAni.GetComponentInChildren<Image>().sprite},
|
||
//Quantity = addAmount,
|
||
StartPoint = new BatchedRewardFlyStartPoint(GetShieldRewardFlySource()),
|
||
EndPoint = new BatchedRewardFlyEndPoint(target),
|
||
IsDestinationRewardStash = true,
|
||
AnimationParamIndex = animationParamIndex
|
||
};
|
||
var task= RewardFlyBatchCtrl.OnRewardFlyRequestAsync(request);
|
||
await Awaiters.Seconds(delayTime);
|
||
callback?.Invoke();
|
||
await task;
|
||
}
|
||
|
||
private async Task PlayReduceShield()
|
||
{
|
||
UIManager.Instance.UI3DCamera.gameObject.SetActive(true);
|
||
shieldGameObject.SetActive(true);
|
||
shieldGameObject.GetComponentInChildren<Animation>()?.Play();
|
||
await Awaiters.Seconds(shieldReduceTime);
|
||
ShowPlayerShield();
|
||
UIManager.Instance.UI3DCamera.gameObject.SetActive(false);
|
||
shieldGameObject.SetActive(false);
|
||
}
|
||
|
||
private async Task PlayAttackTier1()
|
||
{
|
||
_=_playerCell.PlayTimelineAttack1(_playerDirector);
|
||
PlayBossAttackedFx(bossAttackedFxDelay1,1);
|
||
PlayPlayerAttackShake(0);
|
||
PlayBossHpSliderEffect(bossAttackedHpAniDelay1);
|
||
await PlayBossAttacked(bossAttackedDelay1,1);
|
||
}
|
||
private async Task PlayAttackTier2()
|
||
{
|
||
_=_playerCell.PlayTimelineAttack2(_playerDirector);
|
||
PlayBossAttackedFxMultiplier(bossAttackedFxDelay2,2);
|
||
PlayPlayerAttackShake(1);
|
||
PlayPlayerAttackShake(2);
|
||
PlayBossHpSliderEffect(bossAttackedHpAniDelay2);
|
||
await PlayBossAttacked(bossAttackedDelay2, 2);
|
||
}
|
||
private async void PlayBossAttackedFx(float delayTime, int index)
|
||
{
|
||
try
|
||
{
|
||
if (!_eventRectFollowerGraphic)
|
||
return;
|
||
|
||
var rf = _eventRectFollowerGraphic;
|
||
rf.enabled = true;
|
||
rf.gameObject.SetActive(false);
|
||
for (var i = 0; i < rf.transform.childCount; i++)
|
||
rf.transform.GetChild(i).gameObject.SetActive(false);
|
||
await Awaiters.Seconds(delayTime);
|
||
if (_bossCell is EventBossFightTimelineBossCellVideo vb)
|
||
rf.SetTarget(vb.GetHurtAnchor(PickRandomBossHurtAnchorIndex(vb)));
|
||
rf.gameObject.SetActive(true);
|
||
if (index >= 1 && index - 1 < rf.transform.childCount)
|
||
rf.transform.GetChild(index - 1).gameObject.SetActive(true);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
private async void PlayBossAttackedFxMultiplier(float delayTime, int index)
|
||
{
|
||
try
|
||
{
|
||
if (!_eventRectFollowerGraphic)
|
||
return;
|
||
|
||
var rf = _eventRectFollowerGraphic;
|
||
rf.enabled = true;
|
||
rf.gameObject.SetActive(false);
|
||
await Awaiters.Seconds(delayTime);
|
||
var lastIndex = 0;
|
||
for (var i = 0; i < playAttackTier2Count; i++)
|
||
{
|
||
for (var j = 0; j < rf.transform.childCount; j++)
|
||
rf.transform.GetChild(j).gameObject.SetActive(false);
|
||
var targetIndex = 0;
|
||
if (_bossCell is EventBossFightTimelineBossCellVideo vbMul)
|
||
{
|
||
var n = vbMul.bossHurtAnchors != null ? vbMul.bossHurtAnchors.Length : 0;
|
||
targetIndex = PickRandomBossHurtAnchorIndex(vbMul);
|
||
if (n > 1 && targetIndex == lastIndex)
|
||
targetIndex = targetIndex - 1 < 0 ? targetIndex + 1 : targetIndex - 1;
|
||
rf.SetTarget(vbMul.GetHurtAnchor(targetIndex));
|
||
}
|
||
|
||
lastIndex = targetIndex;
|
||
rf.enabled = true;
|
||
rf.gameObject.SetActive(true);
|
||
if (index >= 1 && index - 1 < rf.transform.childCount)
|
||
rf.transform.GetChild(index - 1).gameObject.SetActive(true);
|
||
await Awaiters.Seconds(playAttackTier2Interval);
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
private async Task PlayBossAttacked(float delayTime,int index)
|
||
{
|
||
await Awaiters.Seconds(delayTime);
|
||
await _bossCell.PlayTimelineAttacked(_bossCell.BossTimelineDirector, index);
|
||
await Awaiters.Seconds(bossDeathDelay);
|
||
if (Data.BossRemainHp == 0)
|
||
{
|
||
_isBossDeath = true;
|
||
await _bossCell.PlayTimelineDeath(_bossCell.BossTimelineDirector);
|
||
}
|
||
}
|
||
|
||
private async void PlayBossHpSliderEffect(float delayTime)
|
||
{
|
||
try
|
||
{
|
||
await Awaiters.Seconds(delayTime);
|
||
var fillAmount = (float)Data.BossRemainHp / _stageConfigWithUI.BossHP;
|
||
if (Data.IsLastStage)
|
||
await _imgBossHpBarFinal.DOFillAmount(fillAmount, sliderChangeTime)
|
||
.OnComplete(ShowBossHp).AsyncWaitForCompletion();
|
||
else
|
||
await _imgBossHpBar.DOFillAmount(fillAmount, sliderChangeTime)
|
||
.OnComplete(ShowBossHp).AsyncWaitForCompletion();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
private RectTransform GetShieldRewardFlySource()
|
||
{
|
||
return _shieldAddAni.GetComponentInChildren<Image>().rectTransform;
|
||
}
|
||
private List<RectTransform> GetShieldRewardFlyTarget(int addAmount)
|
||
{
|
||
var targets = new List<RectTransform>();
|
||
for (int i = 0; i < _shields.Length; i++)
|
||
{
|
||
if(!_shields[i].isActiveAndEnabled)
|
||
targets.Add((RectTransform)_shields[i].transform);
|
||
if(targets.Count>=addAmount)
|
||
break;
|
||
}
|
||
return targets;
|
||
}
|
||
private async Task PlayTokenAddFly(int convertTokenCount,RectTransform source,RectTransform sourceText)
|
||
{
|
||
if(convertTokenCount<=0) return;
|
||
await Awaiters.Seconds(tokenAddTime);
|
||
var targetRect = GetTokenRewardFlyTarget();
|
||
var request = new BatchedRewardFlyRequest
|
||
{
|
||
Icon = new BatchedRewardFlyRequestIcon{icon=_imgTokenIcon.sprite},
|
||
Quantity = convertTokenCount,
|
||
StartPoint = new BatchedRewardFlyStartPoint(source,sourceText),
|
||
EndPoint = new BatchedRewardFlyEndPoint(targetRect),
|
||
IsDestinationRewardStash = true,
|
||
AnimationParamIndex = 0
|
||
};
|
||
await RewardFlyBatchCtrl.OnRewardFlyRequestAsync(request);
|
||
ShowTokenAmount();
|
||
}
|
||
private RectTransform GetTokenRewardFlyTarget()
|
||
{
|
||
return _imgTokenIcon.rectTransform;
|
||
}
|
||
#endregion
|
||
|
||
#region bossEffect
|
||
|
||
private async Task PlayBossAttackEffect(bool isReduceShield, bool isReducePlayerHp)
|
||
{
|
||
SetButtonState(false);
|
||
_ = _bossCell.PlayTimelineAttack(_bossCell.BossTimelineDirector);
|
||
var data = _bossCell.BossAttackShakeData;
|
||
if (isReduceShield)
|
||
{
|
||
await Awaiters.Seconds(data.delayShieldTime);
|
||
await PlayReduceShield();
|
||
}
|
||
if(isReducePlayerHp)
|
||
{
|
||
await Awaiters.Seconds(data.delayTime);
|
||
PlayShake(data);
|
||
PlaySceneCrackEffect();
|
||
if (_bossCell.PlayerAttackedFx)
|
||
_bossCell.PlayerAttackedFx.SetActive(true);
|
||
_= _playerCell.PlayTimelineAttacked(_playerDirector);
|
||
await PlayReduceHp();
|
||
if (_bossCell.PlayerAttackedFx)
|
||
_bossCell.PlayerAttackedFx.SetActive(false);
|
||
}
|
||
_isPlayerDeath=Data.PlayerShowHp == 0;
|
||
UpdateFightInfoVisibility();
|
||
await Awaiters.Seconds(delayShowFailPanelTime);
|
||
Manager.CheckStagePlayerState();
|
||
SetButtonState(true);
|
||
}
|
||
|
||
#endregion
|
||
private void OnRewardPanelClose(RewardPanelClose data)
|
||
{
|
||
ShowTokenAmount();
|
||
}
|
||
private async void PlayPlayerAttackShake(int index)
|
||
{
|
||
try
|
||
{
|
||
if (index >= playerShakeData.Count)
|
||
{
|
||
Debug.LogError("playerShakeData index out of range");
|
||
return;
|
||
}
|
||
var data = playerShakeData[index];
|
||
await Awaiters.Seconds(data.delayTime);
|
||
PlayShake(data);
|
||
}
|
||
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
|
||
}
|
||
|
||
private void PlayShake(EventBossFightShakeData data)
|
||
{
|
||
((RectTransform)transform).DOShakeAnchorPos( data.shakeDuration,data.to, data.shakeVibrato, data.shakeRandomness, data.snapping, data.fadeOut, data.randomnessMode)
|
||
.SetEase(data.shakeEase);
|
||
}
|
||
|
||
private void PlaySceneCrackEffect()
|
||
{
|
||
foreach (var obj in _sceneCrackFxs)
|
||
{
|
||
if(obj)
|
||
obj.SetActive(false);
|
||
}
|
||
var index = Random.Range(0, 4);
|
||
var effectObj =_sceneCrackFxs[index];
|
||
if (!effectObj) return;
|
||
var x= Random.Range(minPositonOffset.x, maxPositonOffset.x);
|
||
var y= Random.Range(minPositonOffset.y, maxPositonOffset.y);
|
||
((RectTransform)effectObj.transform).anchoredPosition = new Vector2(x, y);
|
||
effectObj.gameObject.SetActive(true);
|
||
}
|
||
}
|
||
}
|