using DG.Tweening; using GameCore; using Spine.Unity; using TMPro; using UnityEngine; public class MiniBattlePassSecondPanel : MiniBattlePassPanel { TMP_Text text_num1; /// 角色根节点,须在 Content 下;实例化 item 后会 设为同级最末以便后渲染盖在列表上。若受 VerticalLayoutGroup 排布影响,请给该节点加 LayoutElement 并勾选 Ignore Layout。 protected Transform spineRoot; protected SkeletonGraphic spine; RewardItemNew reward; protected override int NormalizedPosition => 0; protected override int showCount => 5; /// /// 与 原 Spine 对齐规则一致:非最后一档时视觉行 = 数据下标 + 1。 /// protected int GetDisplayRowIndexForDataIndex(int dataIndex) { if (miniBPItemDatas == null || miniBPItemDatas.Count == 0) { return 0; } int row = dataIndex; if (row < miniBPItemDatas.Count - 1) { row++; } return row; } protected void SetCharacterRootY(int displayRowIndex) { if (spineRoot == null) { return; } spineRoot.localPosition = new Vector3(spineRoot.localPosition.x, displayRowIndex * itemHeight, 0); } protected virtual void PlayCharacterIdleAnimation() { if (spine != null) { spine.AnimationState.SetAnimation(0, "swimming_idle", true); } } protected virtual void PlayCharacterMoveAnimation() { if (spine != null) { spine.AnimationState.SetAnimation(0, "swimming_move", true); } } protected virtual void OnCharacterScrollArrived() { PlayCharacterIdleAnimation(); } /// /// 开始「追进度」滚动:列表滚动与角色根节点 Y 同步。视频版可重写以在开始前插入转身等。 /// protected virtual void StartCharacterScrollToReward(int startRow, int endRow, float endScrollPos, float duration) { if (spineRoot == null || scrollRect == null) { return; } PlayCharacterMoveAnimation(); scrollRect.DOVerticalNormalizedPos(endScrollPos, duration).SetEase(Ease.Linear); spineRoot.DOLocalMoveY(endRow * itemHeight, duration).OnComplete(OnCharacterScrollArrived); } protected override void Awake() { base.Awake(); reward = transform.Find("root/total_prize/bg/reward").GetComponent(); spineRoot = transform.Find("root/ScrollView/Viewport/Content/spineRoot"); if (spineRoot != null) { var spineTransform = spineRoot.Find("spine"); if (spineTransform != null) { spine = spineTransform.GetComponent(); } } text_num1 = transform.Find("root/total_prize/reward/text_num").GetComponent(); } protected override void OnAfterMiniBattlePassItemsInstantiated() { base.OnAfterMiniBattlePassItemsInstantiated(); if (spineRoot == null || content == null || spineRoot.parent != content) { return; } spineRoot.SetAsLastSibling(); } protected override void Start() { if (miniBP.ItemShow[1] == 1001) { int showCount = 0; var miniBPItemDatas = miniBP.miniBPItemDatas; ItemData itemData; for (int i = 0; i < miniBPItemDatas.Count; i++) { itemData = miniBPItemDatas[i].freeReward; if (itemData != null && itemData.id == 1001) { showCount += itemData.count; } itemData = miniBPItemDatas[i].grandReward; if (itemData != null && itemData.id == 1001) { showCount += itemData.count; } } miniBP.ItemCountShow[1] = showCount; } base.Start(); reward.SetData(miniBP.ItemShow[0], $"x{ConvertTools.GetNumberString(miniBP.ItemCountShow[0])}", true); text_num1.text = $"x{ConvertTools.GetNumberString(miniBP.ItemCountShow[1])}"; } protected override void JumpToIndex() { if (spineRoot == null) { return; } int index = miniBP.Data.showIndex; float startPos = ((index - 2) * 1f / (miniBPItemDatas.Count - showCount)); if (startPos > 1f) { startPos = 1f; } if (startPos < 0f) { startPos = 0f; } scrollRect.verticalNormalizedPosition = startPos; int startRow = GetDisplayRowIndexForDataIndex(miniBP.Data.showIndex); SetCharacterRootY(startRow); if (miniBP.rewardIndex > index) { miniBP.SetOldLevel(); float endPos = ((miniBP.rewardIndex - 2) * 1f / (miniBPItemDatas.Count - showCount)); if (endPos > 1f) { endPos = 1f; } if (endPos < 0f) { endPos = 0f; } const float scrollDuration = 1f; int endRow = GetDisplayRowIndexForDataIndex(miniBP.rewardIndex); StartCharacterScrollToReward(startRow, endRow, endPos, scrollDuration); } else { PlayCharacterIdleAnimation(); } } }