lcy
1 天以前 ca577b96e0022e0ddaa8e106e147e53d8166df1c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
using UnityEngine;
using DG.Tweening;
 
/// <summary>
/// 控制天子看板战箱子(回血时)掉落和收集动画的组件。
/// 动画序列: 抛射弧形 -> 多次弹跳 -> 等待 -> 飞向收集点 -> 销毁
/// </summary>
[RequireComponent(typeof(RectTransform))]
public class TianziBillboradBox : MonoBehaviour
{
    private RectTransform rectTransform;
 
    [Header("1. 抛射阶段 (从Boss位置)")]
    [SerializeField]
    [Tooltip("初始位置的X/Y偏移量(像素单位)。箱子将从[Boss位置 + 偏移]开始抛射。")]
    Vector2 initialPositionOffset = Vector2.zero; // NEW: 初始位置偏移
 
    [SerializeField]
    [Tooltip("箱子抛射的持续时间(秒)。")]
    float throwDuration = 0.6f;
 
    [SerializeField]
    [Tooltip("抛射的缓动动画类型。\n" +
             "Ease.OutQuad: 模拟抛物线,开始快,落地慢。")]
    Ease throwEase = Ease.OutQuad;
 
    [SerializeField]
    [Tooltip("抛射的基础水平距离(像素单位)。")]
    float throwHorizontalDistance = 200f;
 
    [SerializeField]
    [Tooltip("抛射距离的随机变化范围(百分比)。")]
    [Range(0f, 1f)]
    float throwDistanceRandomness = 0.3f;
 
    [SerializeField]
    [Tooltip("抛射的弧形最高点,相对于起点的高度(像素单位)。")]
    float throwArcHeight = 150f; 
 
    [SerializeField]
    [Tooltip("抛射落地的最小垂直距离(像素单位),即比起点低多少。")]
    float minThrowVerticalDrop = 120f; 
 
    [SerializeField]
    [Tooltip("抛射落地的最大垂直距离(像素单位),即比起点低多少。")]
    float maxThrowVerticalDrop = 180f; 
 
 
    [Header("2. 弹跳阶段")]
    [SerializeField]
    [Tooltip("弹跳次数(1-3次)。")]
    [Range(1, 3)]
    int bounceCount = 2;
 
    [SerializeField]
    [Tooltip("第一次弹跳的高度(像素单位)。")]
    float firstBounceHeight = 80f;
 
    [SerializeField]
    [Tooltip("第二次弹跳的高度(像素单位)。")]
    float secondBounceHeight = 50f;
 
    [SerializeField]
    [Tooltip("第三次弹跳的高度(像素单位)。")]
    float thirdBounceHeight = 30f;
 
    [SerializeField]
    [Tooltip("每次弹跳的基础水平距离(像素单位)。")]
    float bounceHorizontalDistance = 100f;
 
    [SerializeField]
    [Tooltip("弹跳距离的随机变化范围(百分比)。")]
    [Range(0f, 1f)]
    float bounceDistanceRandomness = 0.4f;
 
    [SerializeField]
    [Tooltip("每次弹跳的持续时间(秒)。")]
    float bounceDuration = 0.3f;
 
    [SerializeField]
    [Tooltip("弹跳的缓动动画类型。")]
    Ease bounceEase = Ease.OutQuad;
 
    [Header("3. 等待阶段")]
    [SerializeField]
    [Tooltip("弹跳停止后等待的时间(秒)。")]
    float waitAfterBounce = 0.5f;
 
    [Header("4. 收集移动阶段 (飞向终点)")]
    [SerializeField]
    [Tooltip("箱子从地面移动到最终收集位置(rectBoxEnd)所需的时间(秒)。")]
    float moveDuration = 0.4f;
 
    [SerializeField]
    [Tooltip("移动时的缓动动画类型。\n" +
             "Ease.InSine: 实现先慢后快的加速效果。")]
    Ease moveEase = Ease.InSine;
 
    // ----------------------------------------------------------------------
 
    private void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
    }
 
    /// <summary>
    /// 启动箱子动画序列
    /// </summary>
    /// <param name="startWorldPos">动画开始的世界坐标(例如 Boss 头像位置)</param>
    /// <param name="endWorldPos">动画结束的世界坐标(rectBoxEnd 的位置)</param>
    public void StartAnimation(Vector3 startWorldPos, Vector3 endWorldPos)
    {
        /// Debug.Log($"TianziBillboradBox startWorldPos {startWorldPos} endWorldPos {endWorldPos}");
        if (rectTransform == null)
        {
            rectTransform = GetComponent<RectTransform>();
        }
 
        // --- 0. 在开始动画前,将箱子移动到boss的父物体 ---
        Transform currentParent = transform.parent;
        if (currentParent != null)
        {
            Transform bossParent = currentParent.parent; // boss的父物体
            if (bossParent != null)
            {
                transform.SetParent(bossParent);
                transform.localScale = Vector3.one; // 将scale设置为1
            }
        }
 
        // --- 1. 计算并设置初始位置 (应用偏移) ---
        Vector3 actualStartPos = new Vector3(
            startWorldPos.x + initialPositionOffset.x / 100f,
            startWorldPos.y + initialPositionOffset.y / 100f,
            startWorldPos.z
        );
 
        rectTransform.position = actualStartPos; // MODIFIED: 使用偏移后的位置
        gameObject.SetActive(true);
 
        // --- 2. 随机选择抛射方向(左或右)和角度 ---
        bool throwRight = Random.Range(0, 2) == 1;
        float horizontalDirection = throwRight ? 1f : -1f;
 
        // 添加随机角度偏移
        float angleOffset = Random.Range(-45f, 45f);
        float angleRad = angleOffset * Mathf.Deg2Rad;
 
        // 计算带随机性的抛射距离
        float randomThrowDistance = throwHorizontalDistance *
            (1f + Random.Range(-throwDistanceRandomness, throwDistanceRandomness));
 
        // --- 3. 计算抛射终点位置 ---
        //计算随机的垂直下落距离
        float randomVerticalDrop = Random.Range(minThrowVerticalDrop, maxThrowVerticalDrop);
 
        Vector3 throwEndPos = new Vector3(
            actualStartPos.x + randomThrowDistance / 100 * Mathf.Cos(angleRad) * horizontalDirection, // MODIFIED
            actualStartPos.y - randomVerticalDrop / 100, // MODIFIED
            actualStartPos.z
        );
 
        // --- 4. 计算抛射控制点(用于弧形轨迹)---
        Vector3 controlPoint = new Vector3(
            actualStartPos.x + randomThrowDistance / 100 * Mathf.Cos(angleRad) * horizontalDirection * 0.5f, // MODIFIED
            actualStartPos.y + throwArcHeight / 100, // MODIFIED
            actualStartPos.z
        );
 
        // --- 5. 创建一个动画序列 ---
        Sequence animSequence = DOTween.Sequence();
 
        // --- 6. 抛射阶段(弧形轨迹)---
        animSequence.Append(
            rectTransform.DOPath(
                new Vector3[] { actualStartPos, controlPoint, throwEndPos }, // MODIFIED
                throwDuration,
                PathType.CatmullRom
            ).SetEase(throwEase)
        );
 
        // --- 7. 弹跳阶段(向抛射方向继续跳1-3次)---
        Vector3 currentPos = throwEndPos;
        int actualBounceCount = Random.Range(1, bounceCount + 1); // 随机1-3次
 
        for (int i = 0; i < actualBounceCount; i++)
        {
            // 计算当前弹跳的高度
            float currentBounceHeight = i switch
            {
                0 => firstBounceHeight,
                1 => secondBounceHeight,
                _ => thirdBounceHeight
            };
 
            // 计算带随机性的弹跳距离
            float randomBounceDistance = bounceHorizontalDistance *
                (1f + Random.Range(-bounceDistanceRandomness, bounceDistanceRandomness));
 
            // 计算弹跳终点位置(继续向抛射方向移动)
            Vector3 bounceEndPos = new Vector3(
                currentPos.x + randomBounceDistance / 100 * horizontalDirection,
                currentPos.y,
                currentPos.z
            );
 
            // 弹跳控制点(弧形轨迹)
            Vector3 bounceControlPoint = new Vector3(
                currentPos.x + randomBounceDistance / 100 * horizontalDirection * 0.5f,
                currentPos.y + currentBounceHeight / 100,
                currentPos.z
            );
 
            // 添加弹跳动画(弧形轨迹)
            animSequence.Append(
                rectTransform.DOPath(
                    new Vector3[] { currentPos, bounceControlPoint, bounceEndPos },
                    bounceDuration,
                    PathType.CatmullRom
                ).SetEase(bounceEase)
            );
 
            currentPos = bounceEndPos; // 更新当前位置
        }
 
        // --- 8. 等待阶段 ---
        animSequence.AppendInterval(waitAfterBounce);
 
        // --- 9. 移动到终点 ---
        animSequence.Append(
            rectTransform.DOMove(endWorldPos, moveDuration)
                .SetEase(moveEase)
        );
 
        // --- 10. 动画播放完毕后销毁 ---
        animSequence.OnComplete(() =>
        {
            if (this != null && gameObject != null)
            {
                Destroy(gameObject);
            }
        });
 
        // --- 11. 关联生命周期 ---
        animSequence.SetTarget(this);
    }
}