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);
|
}
|
}
|